summaryrefslogtreecommitdiff
path: root/wrapper/wrapper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'wrapper/wrapper.cpp')
-rw-r--r--wrapper/wrapper.cpp740
1 files changed, 451 insertions, 289 deletions
diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp
index 50a3596..6344b77 100644
--- a/wrapper/wrapper.cpp
+++ b/wrapper/wrapper.cpp
@@ -1,51 +1,53 @@
#pragma once
-#include <type_traits>
-#include <msclr\marshal_cppstd.h>
+#include "interop-exception.h"
-#include <rawaccel.hpp>
-#include <rawaccel-version.h>
-#include <utility-rawinput.hpp>
-
-#include "wrapper_io.hpp"
+#include <rawaccel-io.hpp>
+#include <rawaccel-validate.hpp>
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Runtime::InteropServices;
using namespace System::Reflection;
+using namespace System::Runtime::Serialization;
+using namespace Newtonsoft::Json;
+using namespace Newtonsoft::Json::Linq;
-using namespace Windows::Forms;
+namespace ra = rawaccel;
-using namespace Newtonsoft::Json;
+ra::settings default_settings;
[JsonConverter(Converters::StringEnumConverter::typeid)]
public enum class AccelMode
{
- linear, classic, natural, naturalgain, power, motivity, noaccel
+ classic, jump, natural, motivity, power, lut, noaccel
+};
+
+[JsonConverter(Converters::StringEnumConverter::typeid)]
+public enum class SpacedTableMode
+{
+ off, binlog, linear
};
-[JsonObject(ItemRequired = Required::Always)]
[StructLayout(LayoutKind::Sequential)]
-public value struct AccelArgs
+public value struct SpacedTableArgs
{
- double offset;
+ [JsonIgnore]
+ SpacedTableMode mode;
+
[MarshalAs(UnmanagedType::U1)]
- bool legacyOffset;
- double acceleration;
- double scale;
- double limit;
- double exponent;
- double midpoint;
- double weight;
- [JsonProperty("legacyCap")]
- double scaleCap;
- double gainCap;
- [JsonProperty(Required = Required::Default)]
- double speedCap;
+ bool transfer;
+
+ [MarshalAs(UnmanagedType::U1)]
+ unsigned char partitions;
+
+ short num;
+ double start;
+ double stop;
};
+
generic <typename T>
-[JsonObject(ItemRequired = Required::Always)]
[StructLayout(LayoutKind::Sequential)]
public value struct Vec2
{
@@ -53,7 +55,78 @@ public value struct Vec2
T y;
};
-[JsonObject(ItemRequired = Required::Always)]
+[StructLayout(LayoutKind::Sequential)]
+public value struct TableArgs
+{
+ [JsonProperty("Whether points affect velocity (true) or sensitivity (false)")]
+ [MarshalAs(UnmanagedType::U1)]
+ bool velocity;
+
+ [JsonIgnore]
+ int length;
+
+ [MarshalAs(UnmanagedType::ByValArray, SizeConst = ra::ARB_LUT_CAPACITY)]
+ array<Vec2<float>>^ points;
+
+ virtual bool Equals(Object^ ob) override {
+ if (ob->GetType() == this->GetType()) {
+ TableArgs^ other = (TableArgs^)ob;
+
+ if (this->length != other->length) return false;
+ if (this->points == other->points) return true;
+
+ if (unsigned(length) >= ra::ARB_LUT_CAPACITY ||
+ points == nullptr ||
+ other->points == nullptr) {
+ throw gcnew InteropException("invalid table args");
+ }
+
+ for (int i = 0; i < length; i++) {
+ if (points[i].x != other->points[i].x ||
+ points[i].y != other->points[i].y)
+ return false;
+ }
+
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ virtual int GetHashCode() override {
+ return points->GetHashCode() ^ length.GetHashCode();
+ }
+};
+
+[StructLayout(LayoutKind::Sequential)]
+public value struct AccelArgs
+{
+ AccelMode mode;
+
+ [MarshalAs(UnmanagedType::U1)]
+ bool legacy;
+
+ double offset;
+ double cap;
+ double accelClassic;
+ double decayRate;
+ double growthRate;
+ double motivity;
+ double power;
+ double scale;
+ double weight;
+ double exponent;
+ double limit;
+ double midpoint;
+ double smooth;
+
+ [JsonProperty(Required = Required::Default)]
+ SpacedTableArgs spacedTableArgs;
+
+ TableArgs tableData;
+};
+
[StructLayout(LayoutKind::Sequential)]
public value struct DomainArgs
{
@@ -65,20 +138,25 @@ public value struct DomainArgs
[StructLayout(LayoutKind::Sequential, CharSet = CharSet::Unicode)]
public ref struct DriverSettings
{
+ literal double WriteDelayMs = ra::WRITE_DELAY;
literal String^ Key = "Driver settings";
[JsonProperty("Degrees of rotation")]
double rotation;
- [JsonProperty("Degrees of angle snapping", Required = Required::Default)]
+ [JsonProperty("Degrees of angle snapping")]
double snap;
[JsonProperty("Use x as whole/combined accel")]
[MarshalAs(UnmanagedType::U1)]
bool combineMagnitudes;
- [JsonProperty("Accel modes")]
- Vec2<AccelMode> modes;
+ double dpi;
+
+ [JsonIgnore]
+ double minimumSpeed;
+ [JsonProperty("Input Speed Cap")]
+ double maximumSpeed;
[JsonProperty("Accel parameters")]
Vec2<AccelArgs> args;
@@ -86,302 +164,387 @@ public ref struct DriverSettings
[JsonProperty("Sensitivity multipliers")]
Vec2<double> sensitivity;
- [JsonProperty("Negative directional multipliers", Required = Required::Default)]
+ [JsonProperty("Negative directional multipliers")]
Vec2<double> directionalMultipliers;
- [JsonProperty("Stretches domain for horizontal vs vertical inputs", Required = Required::Default)]
+ [JsonProperty("Stretches domain for horizontal vs vertical inputs")]
DomainArgs domainArgs;
- [JsonProperty("Stretches accel range for horizontal vs vertical inputs", Required = Required::Default)]
+ [JsonProperty("Stretches accel range for horizontal vs vertical inputs")]
Vec2<double> rangeXY;
[JsonProperty(Required = Required::Default)]
double minimumTime;
- [JsonProperty("Device ID", Required = Required::Default)]
- [MarshalAs(UnmanagedType::ByValTStr, SizeConst = MAX_DEV_ID_LEN)]
+ [JsonProperty(Required = Required::Default)]
+ double maximumTime;
+
+ [JsonProperty("Ignore devices with matching ID")]
+ [MarshalAs(UnmanagedType::U1)]
+ bool ignore;
+
+ [JsonProperty("Device ID")]
+ [MarshalAs(UnmanagedType::ByValTStr, SizeConst = ra::MAX_DEV_ID_LEN)]
String^ deviceID = "";
bool ShouldSerializeminimumTime()
{
- return minimumTime > 0 && minimumTime != DEFAULT_TIME_MIN;
+ return minimumTime != ra::DEFAULT_TIME_MIN;
+ }
+
+ bool ShouldSerializemaximumTime()
+ {
+ return maximumTime != ra::DEFAULT_TIME_MAX;
}
DriverSettings()
{
- domainArgs = { { 1, 1 }, 2 };
- rangeXY = { 1, 1 };
+ Marshal::PtrToStructure(IntPtr(&default_settings), this);
}
-};
+private:
+ [OnDeserialized]
+ void OnDeserializedMethod(StreamingContext context)
+ {
+ args.x.tableData.length = args.x.tableData.points->Length;
+ args.y.tableData.length = args.y.tableData.points->Length;
-template <typename NativeSettingsFunc>
-void as_native(DriverSettings^ managed_args, NativeSettingsFunc fn)
-{
-#ifndef NDEBUG
- if (Marshal::SizeOf(managed_args) != sizeof(settings))
- throw gcnew InvalidOperationException("setting sizes differ");
-#endif
- settings args;
- Marshal::StructureToPtr(managed_args, (IntPtr)&args, false);
- fn(args);
- if constexpr (!std::is_invocable_v<NativeSettingsFunc, const settings&>) {
- Marshal::PtrToStructure((IntPtr)&args, managed_args);
- }
-}
-
-DriverSettings^ get_default()
-{
- DriverSettings^ managed = gcnew DriverSettings();
- as_native(managed, [](settings& args) {
- args = {};
- });
- return managed;
-}
-
-void set_active(DriverSettings^ managed)
-{
- as_native(managed, [](const settings& args) {
- wrapper_io::writeToDriver(args);
- });
-}
+ array<Vec2<float>>::Resize(args.x.tableData.points, ra::ARB_LUT_CAPACITY);
+ array<Vec2<float>>::Resize(args.y.tableData.points, ra::ARB_LUT_CAPACITY);
+ }
-DriverSettings^ get_active()
-{
- DriverSettings^ managed = gcnew DriverSettings();
- as_native(managed, [](settings& args) {
- wrapper_io::readFromDriver(args);
- });
- return managed;
-}
-
-void update_modifier(mouse_modifier& mod, DriverSettings^ managed, vec2<si_pair*> luts = {})
-{
- as_native(managed, [&](const settings& args) {
- mod = { args, luts };
- });
-}
+ [OnSerializing]
+ void OnSerializingMethod(StreamingContext context)
+ {
+ array<Vec2<float>>::Resize(args.x.tableData.points, args.x.tableData.length);
+ array<Vec2<float>>::Resize(args.y.tableData.points, args.y.tableData.length);
+ }
+
+ [OnSerialized]
+ void OnSerializedMethod(StreamingContext context)
+ {
+ array<Vec2<float>>::Resize(args.x.tableData.points, ra::ARB_LUT_CAPACITY);
+ array<Vec2<float>>::Resize(args.y.tableData.points, ra::ARB_LUT_CAPACITY);
+ }
-using error_list_t = Collections::Generic::List<String^>;
+};
-error_list_t^ get_accel_errors(AccelMode mode, AccelArgs^ args)
+[JsonObject(ItemRequired = Required::Always)]
+public ref struct LutBase
{
- accel_mode mode_native = (accel_mode)mode;
-
- auto is_mode = [mode_native](auto... modes) {
- return ((mode_native == modes) || ...);
- };
-
- using am = accel_mode;
+ [JsonConverter(Converters::StringEnumConverter::typeid)]
+ enum class Mode
+ {
+ logarithmic, linear
+ } mode;
- auto error_list = gcnew error_list_t();
-
- if (args->acceleration > 10 && is_mode(am::natural, am::naturalgain))
- error_list->Add("acceleration can not be greater than 10");
- else if (args->acceleration == 0 && is_mode(am::naturalgain))
- error_list->Add("acceleration must be positive");
- else if (args->acceleration < 0) {
- bool additive = mode_native < am::power;
- if (additive) error_list->Add("acceleration can not be negative, use a negative weight to compensate");
- else error_list->Add("acceleration can not be negative");
- }
-
- if (args->scale <= 0)
- error_list->Add("scale must be positive");
+ virtual void SetArgs(AccelArgs%) {}
+ virtual void SetData(ra::accel_union&) {}
+};
- if (args->exponent <= 1 && is_mode(am::classic))
- error_list->Add("exponent must be greater than 1");
- else if (args->exponent <= 0)
- error_list->Add("exponent must be positive");
- if (args->limit <= 1)
- error_list->Add("limit must be greater than 1");
+[JsonObject(ItemRequired = Required::Always)]
+public ref struct SpacedLut abstract : public LutBase
+{
+ [JsonProperty("Whether points affect velocity (true) or sensitivity (false)")]
+ bool transfer;
- if (args->midpoint <= 0)
- error_list->Add("midpoint must be positive");
+ double start;
+ double stop;
+ array<float>^ data;
- if (args->offset < 0)
- error_list->Add("offset can not be negative");
+ void SetArgsBase(AccelArgs% args)
+ {
+ args.spacedTableArgs.transfer = transfer;
+ args.spacedTableArgs.start = start;
+ args.spacedTableArgs.stop = stop;
+ }
- return error_list;
-}
+ void SetDataBase(ra::accel_union& accel)
+ {
+ if (size_t(data->LongLength) > ra::SPACED_LUT_CAPACITY) {
+ throw gcnew InteropException("data is too large");
+ }
+ }
+};
-error_list_t^ get_other_errors(DriverSettings^ settings)
+[JsonObject(ItemRequired = Required::Always)]
+public ref struct LinearLut sealed : public SpacedLut
{
- auto error_list = gcnew error_list_t();
+ LinearLut()
+ {
+ }
- if (settings->rangeXY.x <= 0 || settings->rangeXY.y <= 0)
+ LinearLut(const ra::linear_lut& table)
{
- error_list->Add("range values must be positive");
+ 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->domainArgs.domainXY.x <= 0 || settings->domainArgs.domainXY.y <= 0)
+ virtual void SetArgs(AccelArgs% args) override
{
- error_list->Add("domain values must be positive");
+ SetArgsBase(args);
+ args.spacedTableArgs.num = data->Length;
+ args.spacedTableArgs.mode = SpacedTableMode::linear;
}
- if (settings->domainArgs.lpNorm <= 0)
+ virtual void SetData(ra::accel_union& accel) override
{
- error_list->Add("lp norm must be positive");
+ SetDataBase(accel);
+ pin_ptr<float> pdata = &data[0];
+ std::memcpy(&accel.lin_lut.data, pdata, sizeof(float) * data->Length);
}
-
- return error_list;
-}
+};
-public ref class SettingsErrors
+[JsonObject(ItemRequired = Required::Always)]
+public ref struct BinLogLut sealed : public SpacedLut
{
-public:
- error_list_t^ x;
- error_list_t^ y;
- error_list_t^ other;
+ short num;
- bool Empty()
+ BinLogLut()
{
- return (x == nullptr || x->Count == 0) &&
- (y == nullptr || y->Count == 0) &&
- (other == nullptr || other->Count == 0);
}
- virtual String^ ToString() override
+ BinLogLut(const ra::binlog_lut& table)
{
- if (x == nullptr) throw;
+ 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);
+ }
- Text::StringBuilder^ sb = gcnew Text::StringBuilder();
+ virtual void SetArgs(AccelArgs% args) override
+ {
+ SetArgsBase(args);
+ args.spacedTableArgs.num = num;
+ args.spacedTableArgs.mode = SpacedTableMode::binlog;
+ }
- if (y == nullptr) // assume combineMagnitudes
- {
- for each (String^ str in x)
- {
- sb->AppendLine(str);
- }
- }
- else
- {
- for each (String^ str in x)
- {
- sb->AppendFormat("x: {0}\n", str);
- }
- for each (String^ str in y)
- {
- sb->AppendFormat("y: {0}\n", str);
- }
- }
+ virtual void SetData(ra::accel_union& accel) override
+ {
+ SetDataBase(accel);
- for each (String ^ str in other)
- {
- sb->AppendLine(str);
+ if (data->Length != 1 + num * (int(stop) - int(start))) {
+ throw gcnew InteropException("size of data does not match args");
}
-
- return sb->ToString();
+
+ pin_ptr<float> pdata = &data[0];
+ std::memcpy(&accel.log_lut.data, pdata, sizeof(float) * data->Length);
}
};
-public ref struct RawInputInterop
-{
- static void AddHandlesFromID(String^ deviceID, List<IntPtr>^ rawInputHandles)
+public ref struct RaConvert {
+
+ static DriverSettings^ Settings(String^ json)
{
- try
- {
- std::vector<HANDLE> nativeHandles = rawinput_handles_from_dev_id(
- msclr::interop::marshal_as<std::wstring>(deviceID));
+ 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);
- for (auto nh : nativeHandles) rawInputHandles->Add(IntPtr(nh));
+ if ((Object^)jObject == nullptr) {
+ throw gcnew JsonException("bad json");
}
- catch (const std::exception& e)
- {
- throw gcnew System::Exception(gcnew String(e.what()));
+
+ LutBase^ base = NonNullable<LutBase^>(jObject);
+
+ switch (base->mode) {
+ case LutBase::Mode::logarithmic:
+ return NonNullable<BinLogLut^>(jObject);
+ case LutBase::Mode::linear:
+ return NonNullable<LinearLut^>(jObject);
+ default:
+ throw gcnew NotImplementedException();
}
}
- static List<String^>^ GetDeviceIDs()
+ static String^ Table(LutBase^ lut)
{
- try
- {
- auto managed = gcnew List<String^>();
+ auto serializerSettings = gcnew JsonSerializerSettings();
+ return JsonConvert::SerializeObject(
+ lut, lut->GetType(), Formatting::Indented, serializerSettings);
+ };
- for (auto&& id : rawinput_dev_id_list())
- {
- managed->Add(msclr::interop::marshal_as<String^>(id));
- }
+ 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) {}
- return managed;
+ 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);
}
- catch (const std::exception& e)
- {
- throw gcnew System::Exception(gcnew String(e.what()));
+ else {
+ baseSettings = gcnew DriverSettings();
+ }
+
+ if (xTableJson || yTableJson) {
+ baseSettings->combineMagnitudes = !byComponent;
+ }
+
+ if (xTableJson) {
+ tables.x = RaConvert::Table(xTableJson);
+ tables.x->SetArgs(baseSettings->args.x);
+ }
+
+ if (yTableJson) {
+ if (Object::ReferenceEquals(yTableJson, xTableJson)) {
+ tables.y = tables.x;
+ }
+ else {
+ tables.y = RaConvert::Table(yTableJson);
+ }
+
+ tables.y->SetArgs(baseSettings->args.y);
}
}
};
-public ref struct DriverInterop
+public ref class SettingsErrors
{
- literal double WriteDelayMs = WRITE_DELAY;
- static initonly DriverSettings^ DefaultSettings = get_default();
+public:
- static DriverSettings^ GetActiveSettings()
- {
- return get_active();
- }
+ List<String^>^ list;
+ int countX;
+ int countY;
- static void Write(DriverSettings^ args)
- {
- set_active(args);
- }
+ delegate void MsgHandler(const char*);
- static DriverSettings^ GetDefaultSettings()
+ void Add(const char* msg)
{
- return get_default();
+ list->Add(gcnew String(msg));
}
- static SettingsErrors^ GetSettingsErrors(DriverSettings^ args)
+ SettingsErrors(ExtendedSettings^ settings) :
+ SettingsErrors(settings->baseSettings) {}
+
+ SettingsErrors(DriverSettings^ settings)
{
- auto errors = gcnew SettingsErrors();
+ MsgHandler^ del = gcnew MsgHandler(this, &SettingsErrors::Add);
+ GCHandle gch = GCHandle::Alloc(del);
+ auto fp = static_cast<void (*)(const char*)>(
+ Marshal::GetFunctionPointerForDelegate(del).ToPointer());
- errors->x = get_accel_errors(args->modes.x, args->args.x);
+ ra::settings* args_ptr = new ra::settings();
+ Marshal::StructureToPtr(settings, (IntPtr)args_ptr, false);
- if (!args->combineMagnitudes) {
- errors->y = get_accel_errors(args->modes.y, args->args.y);
- }
+ list = gcnew List<String^>();
+ auto [cx, cy, _] = ra::valid(*args_ptr, fp);
+ countX = cx;
+ countY = cy;
- errors->other = get_other_errors(args);
+ gch.Free();
+ delete args_ptr;
+ }
- return errors;
+ bool Empty()
+ {
+ return list->Count == 0;
}
+ virtual String^ ToString() override
+ {
+ Text::StringBuilder^ sb = gcnew Text::StringBuilder();
+ for each (auto s in list->GetRange(0, countX))
+ {
+ sb->AppendFormat("x: {0}\n", s);
+ }
+ for each (auto s in list->GetRange(countX, countY))
+ {
+ sb->AppendFormat("y: {0}\n", s);
+ }
+ for each (auto s in list->GetRange(countY, list->Count))
+ {
+ sb->AppendLine(s);
+ }
- static error_list_t^ GetAccelErrors(AccelMode mode, AccelArgs^ args)
- {
- return get_accel_errors(mode, args);
+ return sb->ToString();
}
};
+struct instance_t {
+ ra::io_t data;
+ vec2<ra::accel_invoker> inv;
+};
+
public ref class ManagedAccel
{
- mouse_modifier* const modifier_instance = new mouse_modifier();
-#ifdef RA_LOOKUP
- si_pair* const lut_x = new si_pair[LUT_SIZE];
- si_pair* const lut_y = new si_pair[LUT_SIZE];
-#else
- si_pair* lut_x = nullptr;
- si_pair* lut_y = nullptr;
-#endif
+ instance_t* const instance = new instance_t();
public:
+ ManagedAccel() {}
+
+ ManagedAccel(ExtendedSettings^ settings)
+ {
+ Settings = settings;
+ }
virtual ~ManagedAccel()
{
- delete modifier_instance;
- delete[] lut_x;
- delete[] lut_y;
+ delete instance;
}
!ManagedAccel()
{
- delete modifier_instance;
- delete[] lut_x;
- delete[] lut_y;
+ delete instance;
}
Tuple<double, double>^ Accelerate(int x, int y, double time)
@@ -390,90 +553,89 @@ public:
(double)x,
(double)y
};
- modifier_instance->modify(in_out_vec, time);
+
+ instance->data.mod.modify(in_out_vec, instance->inv, time);
return gcnew Tuple<double, double>(in_out_vec.x, in_out_vec.y);
}
- void UpdateFromSettings(DriverSettings^ args)
+ void Activate()
{
- update_modifier(
- *modifier_instance,
- args,
- vec2<si_pair*>{ lut_x, lut_y }
- );
+ try {
+ ra::write(instance->data);
+ }
+ catch (const ra::error& e) {
+ throw gcnew InteropException(e);
+ }
}
- static ManagedAccel^ GetActiveAccel()
+ property ExtendedSettings^ Settings
{
- settings args;
- wrapper_io::readFromDriver(args);
-
- auto active = gcnew ManagedAccel();
- *active->modifier_instance = {
- args
- , vec2<si_pair*> { active->lut_x, active->lut_y }
- };
- return active;
- }
-};
-
-public ref struct RawAccelVersion
-{
- literal String^ value = RA_VER_STRING;
-};
-
-public ref struct VersionException : public Exception
-{
-public:
- VersionException() {}
- VersionException(String^ what) : Exception(what) {}
-};
-
-Version^ convert(rawaccel::version_t v)
-{
- return gcnew Version(v.major, v.minor, v.patch, 0);
-}
+ ExtendedSettings^ get()
+ {
+ auto settings = gcnew ExtendedSettings();
+ Marshal::PtrToStructure(IntPtr(&instance->data.args), settings->baseSettings);
+ settings->tables.x = extract(instance->data.args.argsv.x.spaced_args.mode,
+ instance->data.mod.accel.x);
+ settings->tables.y = extract(instance->data.args.argsv.y.spaced_args.mode,
+ instance->data.mod.accel.y);
+ return settings;
+ }
-public ref struct VersionHelper
-{
+ void set(ExtendedSettings^ val)
+ {
+ Marshal::StructureToPtr(val->baseSettings, IntPtr(&instance->data.args), false);
+ instance->data.mod = { instance->data.args };
+ instance->inv = ra::invokers(instance->data.args);
- static Version^ ValidateAndGetDriverVersion(Version^ wrapperTarget)
- {
- Version^ wrapperActual = VersionHelper::typeid->Assembly->GetName()->Version;
+ if (val->tables.x) {
+ val->tables.x->SetData(instance->data.mod.accel.x);
+ }
- if (wrapperTarget != wrapperActual) {
- throw gcnew VersionException("version mismatch, expected wrapper.dll v" + wrapperActual);
+ if (val->tables.y) {
+ val->tables.y->SetData(instance->data.mod.accel.y);
+ }
}
- version_t drv_ver;
+ }
+ static ManagedAccel^ GetActive()
+ {
try {
- wrapper_io::getDriverVersion(drv_ver);
+ auto active = gcnew ManagedAccel();
+ ra::read(active->instance->data);
+ active->instance->inv = ra::invokers(active->instance->data.args);
+ return active;
}
- catch (DriverNotInstalledException^ ex) {
- throw gcnew VersionException(ex->Message);
+ catch (const ra::error& e) {
+ throw gcnew InteropException(e);
}
- catch (DriverIOException^) {
- // Assume version ioctl is unimplemented (driver version < v1.3.0)
- throw gcnew VersionException("driver version is out of date\n\nrun installer.exe to reinstall");
+ }
+
+private:
+ LutBase^ extract(ra::spaced_lut_mode mode, ra::accel_union& au)
+ {
+ switch (mode) {
+ case ra::spaced_lut_mode::off: return nullptr;
+ case ra::spaced_lut_mode::linear: return gcnew LinearLut(au.lin_lut);
+ case ra::spaced_lut_mode::binlog: return gcnew BinLogLut(au.log_lut);
+ default: throw gcnew NotImplementedException();
}
+ }
+};
- Version^ drv_ver_managed = convert(drv_ver);
+public ref struct VersionHelper
+{
+ literal String^ VersionString = RA_VER_STRING;
- if (drv_ver_managed < convert(min_driver_version)) {
- throw gcnew VersionException(
- String::Format("driver version is out of date (v{0})\n\nrun installer.exe to reinstall",
- drv_ver_managed));
- }
- else if (drv_ver_managed > wrapperActual) {
- throw gcnew VersionException(
- String::Format("newer driver version is installed (v{0})",
- drv_ver_managed));
+ static Version^ ValidOrThrow()
+ {
+ try {
+ ra::version_t v = ra::valid_version_or_throw();
+ return gcnew Version(v.major, v.minor, v.patch, 0);
}
- else {
- return drv_ver_managed;
+ catch (const ra::error& e) {
+ throw gcnew InteropException(e);
}
}
-
};