summaryrefslogtreecommitdiff
path: root/wrapper
diff options
context:
space:
mode:
authora1xd <[email protected]>2021-04-06 01:21:42 -0400
committera1xd <[email protected]>2021-04-06 01:21:42 -0400
commit7c1f14845bc948e9ea25908e96099203d9433a69 (patch)
treeeadfae6ec0a775a35c29807bde3c20be8160e034 /wrapper
parentLUT text layout (diff)
downloadrawaccel-7c1f14845bc948e9ea25908e96099203d9433a69.tar.xz
rawaccel-7c1f14845bc948e9ea25908e96099203d9433a69.zip
update wrapper + writer to handle lut
grapher is building but applying options still broken for the most part
Diffstat (limited to 'wrapper')
-rw-r--r--wrapper/input.cpp74
-rw-r--r--wrapper/interop-exception.h21
-rw-r--r--wrapper/wrapper.cpp414
-rw-r--r--wrapper/wrapper.vcxproj3
-rw-r--r--wrapper/wrapper.vcxproj.filters6
5 files changed, 375 insertions, 143 deletions
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">