From 5b659e1cfbc4b8fbbd2f2bf41dc716929976c77d Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Sat, 28 Aug 2021 01:19:18 -0400 Subject: add per-device configuration adds input and [in, out] cap for classic mode adds input cap for power mode change wrapper/input, now gets useful device names change (now dev specific) dpi to adjust sensitivity change y sensitivity to y/x ratio remove spaced LUTs grapher and convert do not build --- wrapper/input.cpp | 119 ++++--- wrapper/input.h | 110 ++++-- wrapper/wrapper.cpp | 874 ++++++++++++++++++++++++++---------------------- wrapper/wrapper.vcxproj | 7 +- 4 files changed, 617 insertions(+), 493 deletions(-) (limited to 'wrapper') diff --git a/wrapper/input.cpp b/wrapper/input.cpp index 3ce257a..e34af4a 100644 --- a/wrapper/input.cpp +++ b/wrapper/input.cpp @@ -1,79 +1,90 @@ #include "input.h" -#include "interop-exception.h" - -#include -#include using namespace System; using namespace System::Collections::Generic; +using namespace System::Runtime::InteropServices; -std::vector rawinput_handles_from_id(const std::wstring& device_id) -{ - std::vector handles; +[StructLayout(LayoutKind::Sequential, CharSet = CharSet::Unicode)] +public ref struct RawInputDevice { + System::IntPtr handle; - rawinput_foreach([&](const auto& dev) { - if (dev.id == device_id) handles.push_back(dev.handle); - }); + [MarshalAs(UnmanagedType::ByValTStr, SizeConst = MAX_NAME_LEN)] + System::String^ name; - return handles; -} + [MarshalAs(UnmanagedType::ByValTStr, SizeConst = MAX_DEV_ID_LEN)] + System::String^ id; +}; -std::vector rawinput_id_list() +static int CompareByID(RawInputDevice^ x, RawInputDevice^ y) { - std::vector ids; - - rawinput_foreach([&](const auto& dev) { - ids.push_back(dev.id); - }); - - std::sort(ids.begin(), ids.end()); - ids.erase(std::unique(ids.begin(), ids.end()), ids.end()); - return ids; + return String::Compare(x->id, y->id); } -public ref struct RawInputInteropException : InteropException { - RawInputInteropException(System::String^ what) : - InteropException(what) {} - RawInputInteropException(const char* what) : - InteropException(what) {} - RawInputInteropException(const std::exception& e) : - InteropException(e) {} -}; +public ref struct MultiHandleDevice { + System::String^ name; + System::String^ id; + List^ handles; -public ref struct RawInputInterop -{ - static void AddHandlesFromID(String^ deviceID, List^ rawInputHandles) + // Each element in the list returned has a distinct id + // https://docs.microsoft.com/en-us/windows-hardware/drivers/install/device-ids + static List^ GetList() { - try - { - std::vector nativeHandles = rawinput_handles_from_id( - msclr::interop::marshal_as(deviceID)); + return ListMaker::MakeList(); + } - for (auto nh : nativeHandles) rawInputHandles->Add(IntPtr(nh)); - } - catch (const std::exception& e) + ref class ListMaker { + List^ devices = gcnew List(); + + delegate void NativeDevHandler(rawinput_device&); + + void Add(rawinput_device& dev) { - throw gcnew RawInputInteropException(e); + devices->Add(Marshal::PtrToStructure(IntPtr(&dev))); } - } - static List^ GetDeviceIDs() - { - try + ListMaker() {} + public: + static List^ MakeList() { - auto ids = gcnew List(); + auto maker = gcnew ListMaker(); + NativeDevHandler^ del = gcnew NativeDevHandler(maker, &Add); + GCHandle gch = GCHandle::Alloc(del); + auto fp = static_cast( + Marshal::GetFunctionPointerForDelegate(del).ToPointer()); + rawinput_foreach(fp); + gch.Free(); - for (auto&& name : rawinput_id_list()) - { - ids->Add(msclr::interop::marshal_as(name)); + auto ret = gcnew List(); + auto count = maker->devices->Count; + auto first = 0; + auto last = 0; + + if (count > 0) { + maker->devices->Sort(gcnew Comparison(&CompareByID)); + while (++last != count) { + if (!String::Equals(maker->devices[first]->id, maker->devices[last]->id)) { + auto range = maker->devices->GetRange(first, last - first); + ret->Add(gcnew MultiHandleDevice(range)); + first = last; + } + } + auto range = maker->devices->GetRange(first, last - first); + ret->Add(gcnew MultiHandleDevice(range)); } - return ids; + return ret; } - catch (const std::exception& e) - { - throw gcnew RawInputInteropException(e); + }; + +private: + MultiHandleDevice(IEnumerable^ seq) + { + auto it = seq->GetEnumerator(); + if (it->MoveNext()) { + name = it->Current->name; + id = it->Current->id; + handles = gcnew List(); + do handles->Add(it->Current->handle); while (it->MoveNext()); } } - }; diff --git a/wrapper/input.h b/wrapper/input.h index c83dca8..a931904 100644 --- a/wrapper/input.h +++ b/wrapper/input.h @@ -1,77 +1,127 @@ #pragma once #pragma comment(lib, "cfgmgr32.lib") +#pragma comment(lib, "hid.lib") +#pragma comment(lib, "User32.lib") -#include -#include +#include #include #include #include #include // needed for devpkey.h to parse properly #include +#include + +inline constexpr size_t MAX_DEV_ID_LEN = 200; +inline constexpr size_t MAX_NAME_LEN = 256; +inline constexpr UINT RI_ERROR = -1; struct rawinput_device { - HANDLE handle; - std::wstring id; + HANDLE handle = nullptr; // rawinput handle + WCHAR name[MAX_NAME_LEN] = {}; // manufacturer + product + WCHAR id[MAX_DEV_ID_LEN] = {}; // hwid formatted device id }; template void rawinput_foreach(Func fn, DWORD device_type = RIM_TYPEMOUSE) { - const UINT RI_ERROR = -1; - - // get number of devices - UINT num_devs = 0; - if (GetRawInputDeviceList(NULL, &num_devs, sizeof(RAWINPUTDEVICELIST)) != 0) { - throw std::system_error(GetLastError(), std::system_category(), "GetRawInputDeviceList failed"); - } - - auto dev_list = std::vector(num_devs); + const size_t HID_STR_MAX_LEN = 127; + + auto starts_with = [](auto&& a, auto&& b) { + return b.size() <= a.size() && std::equal(b.begin(), b.end(), a.begin()); + }; + + auto get_dev_list = []() -> std::vector { + UINT elem_size = sizeof(RAWINPUTDEVICELIST); + UINT num_devs = 0; + + if (GetRawInputDeviceList(NULL, &num_devs, elem_size) == 0) { + auto dev_list = std::vector(num_devs); + + if (GetRawInputDeviceList(&dev_list[0], &num_devs, elem_size) != RI_ERROR) { + return dev_list; + } + } - if (GetRawInputDeviceList(&dev_list[0], &num_devs, sizeof(RAWINPUTDEVICELIST)) == RI_ERROR) { - return; - } + return {}; + }; - std::wstring name; + std::wstring interface_name; rawinput_device dev; DEVPROPTYPE prop_type; CONFIGRET cm_res; + WCHAR product_str_buf[HID_STR_MAX_LEN] = {}; - for (auto [handle, dev_type] : dev_list) { + for (auto [handle, dev_type] : get_dev_list()) { if (dev_type != device_type) continue; - // get interface name length + dev.handle = handle; + + // get interface name UINT name_len = 0; if (GetRawInputDeviceInfoW(handle, RIDI_DEVICENAME, NULL, &name_len) == RI_ERROR) { continue; } - name.resize(name_len); + interface_name.resize(name_len); - if (GetRawInputDeviceInfoW(handle, RIDI_DEVICENAME, &name[0], &name_len) == RI_ERROR) { + if (GetRawInputDeviceInfoW(handle, RIDI_DEVICENAME, &interface_name[0], &name_len) == RI_ERROR) { continue; } - // get sizeof device instance id + // make name from vendor + product + HANDLE hid_dev_object = CreateFileW( + &interface_name[0], 0, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + + if (hid_dev_object != INVALID_HANDLE_VALUE) { + + if (HidD_GetProductString(hid_dev_object, product_str_buf, HID_STR_MAX_LEN)) { + auto product_sv = std::wstring_view(product_str_buf); + + if (HidD_GetManufacturerString(hid_dev_object, dev.name, HID_STR_MAX_LEN)) { + auto manufacturer_sv = std::wstring_view(dev.name); + + if (starts_with(product_sv, manufacturer_sv)) { + wcsncpy_s(dev.name, product_str_buf, HID_STR_MAX_LEN); + } + else { + auto last = manufacturer_sv.size(); + dev.name[last] = L' '; + wcsncpy_s(dev.name + last + 1, HID_STR_MAX_LEN, product_str_buf, HID_STR_MAX_LEN); + } + } + else { + wcsncpy_s(dev.name, product_str_buf, HID_STR_MAX_LEN); + } + } + else { + dev.name[0] = L'\0'; + } + + CloseHandle(hid_dev_object); + } + else { + dev.name[0] = L'\0'; + } + + // get device instance id ULONG id_size = 0; - cm_res = CM_Get_Device_Interface_PropertyW(&name[0], &DEVPKEY_Device_InstanceId, + cm_res = CM_Get_Device_Interface_PropertyW(&interface_name[0], &DEVPKEY_Device_InstanceId, &prop_type, NULL, &id_size, 0); if (cm_res != CR_BUFFER_SMALL && cm_res != CR_SUCCESS) continue; - dev.id.resize((id_size + 1) / 2); - - cm_res = CM_Get_Device_Interface_PropertyW(&name[0], &DEVPKEY_Device_InstanceId, + cm_res = CM_Get_Device_Interface_PropertyW(&interface_name[0], &DEVPKEY_Device_InstanceId, &prop_type, reinterpret_cast(&dev.id[0]), &id_size, 0); if (cm_res != CR_SUCCESS) continue; // pop instance id - auto instance_delim_pos = dev.id.find_last_of('\\'); - if (instance_delim_pos != std::string::npos) dev.id.resize(instance_delim_pos); - - dev.handle = handle; + auto instance_delim_pos = std::wstring_view(dev.id).find_last_of(L'\\'); + if (instance_delim_pos != std::string::npos) { + dev.id[instance_delim_pos] = L'\0'; + } fn(dev); } diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp index 4e6c4f1..fba66fa 100644 --- a/wrapper/wrapper.cpp +++ b/wrapper/wrapper.cpp @@ -15,38 +15,36 @@ using namespace Newtonsoft::Json::Linq; namespace ra = rawaccel; -ra::settings default_settings; +ra::driver_settings default_driver_settings; +ra::device_settings default_device_settings; -[JsonConverter(Converters::StringEnumConverter::typeid)] -public enum class AccelMode +public ref struct VersionHelper { - classic, jump, natural, motivity, power, lut, noaccel + literal String^ VersionString = RA_VER_STRING; + + static Version^ ValidOrThrow() + { + try { + ra::version_t v = ra::valid_version_or_throw(); + return gcnew Version(v.major, v.minor, v.patch, 0); + } + catch (const ra::error& e) { + throw gcnew InteropException(e); + } + } }; [JsonConverter(Converters::StringEnumConverter::typeid)] -public enum class SpacedTableMode +public enum class AccelMode { - off, binlog, linear + classic, jump, natural, motivity, power, lut, noaccel }; -[StructLayout(LayoutKind::Sequential)] -public value struct SpacedTableArgs -{ - [JsonIgnore] - SpacedTableMode mode; - - [MarshalAs(UnmanagedType::U1)] - bool transfer; - - [MarshalAs(UnmanagedType::U1)] - unsigned char partitions; - - short num; - double start; - double stop; +[JsonConverter(Converters::StringEnumConverter::typeid)] +public enum class ClassicCapMode { + in_out, input, output }; - generic [StructLayout(LayoutKind::Sequential)] public value struct Vec2 @@ -55,443 +53,318 @@ public value struct Vec2 T y; }; -[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>^ 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 { + literal int MaxLutPoints = ra::LUT_POINTS_CAPACITY; + AccelMode mode; + [JsonProperty("Gain / Velocity")] [MarshalAs(UnmanagedType::U1)] - bool legacy; + bool gain; double offset; - double cap; - double accelClassic; + double acceleration; double decayRate; double growthRate; double motivity; - double power; + double exponentClassic; double scale; double weight; - double exponent; + double exponentPower; double limit; double midpoint; double smooth; - [JsonProperty(Required = Required::Default)] - SpacedTableArgs spacedTableArgs; + [JsonProperty("Cap / Jump")] + Vec2 cap; - TableArgs tableData; -}; + [JsonProperty("Cap mode")] + ClassicCapMode capMode; -[StructLayout(LayoutKind::Sequential)] -public value struct DomainArgs -{ - Vec2 domainXY; - double lpNorm; + [JsonIgnore] + int length; + + [MarshalAs(UnmanagedType::ByValArray, SizeConst = ra::LUT_RAW_DATA_CAPACITY)] + array^ data; + + [OnDeserialized] + void OnDeserializedMethod(StreamingContext context) + { + // data->Length must match SizeConst when marshalling + length = data->Length; + array::Resize(data, ra::LUT_RAW_DATA_CAPACITY); + } }; [JsonObject(ItemRequired = Required::Always)] [StructLayout(LayoutKind::Sequential, CharSet = CharSet::Unicode)] -public ref struct DriverSettings +public ref struct Profile { - literal double WriteDelayMs = ra::WRITE_DELAY; - literal String^ Key = "Driver settings"; - - [JsonProperty("Degrees of rotation")] - double rotation; - - [JsonProperty("Degrees of angle snapping")] - double snap; + [MarshalAs(UnmanagedType::ByValTStr, SizeConst = ra::MAX_NAME_LEN)] + System::String^ name; - [JsonProperty("Use x as whole/combined accel")] + [JsonProperty("Whole/combined accel (set false for 'by component' mode)")] [MarshalAs(UnmanagedType::U1)] bool combineMagnitudes; - double dpi; - - [JsonIgnore] - double minimumSpeed; - [JsonProperty("Input Speed Cap")] - double maximumSpeed; - - [JsonProperty("Accel parameters")] - Vec2 args; - - [JsonProperty("Sensitivity multipliers")] - Vec2 sensitivity; - - [JsonProperty("Negative directional multipliers")] - Vec2 directionalMultipliers; + double lpNorm; [JsonProperty("Stretches domain for horizontal vs vertical inputs")] - DomainArgs domainArgs; - + Vec2 domainXY; [JsonProperty("Stretches accel range for horizontal vs vertical inputs")] Vec2 rangeXY; - [JsonProperty(Required = Required::Default)] - double minimumTime; + [JsonProperty("Sensitivity multiplier")] + double sensitivity; - [JsonProperty(Required = Required::Default)] - double maximumTime; + [JsonProperty("Y/X sensitivity ratio (vertical sens multiplier)")] + double yxSensRatio; - [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 = ""; + [JsonProperty("Whole or horizontal accel parameters")] + AccelArgs argsX; + [JsonProperty("Vertical accel parameters")] + AccelArgs argsY; - bool ShouldSerializeminimumTime() - { - return minimumTime != ra::DEFAULT_TIME_MIN; - } - - bool ShouldSerializemaximumTime() - { - return maximumTime != ra::DEFAULT_TIME_MAX; - } - - DriverSettings() - { - Marshal::PtrToStructure(IntPtr(&default_settings), this); - } + [JsonIgnore] + double minimumSpeed; + [JsonProperty("Input Speed Cap")] + double maximumSpeed; -private: - [OnDeserialized] - void OnDeserializedMethod(StreamingContext context) - { - args.x.tableData.length = args.x.tableData.points->Length; - args.y.tableData.length = args.y.tableData.points->Length; + [JsonProperty("Negative directional multipliers")] + Vec2 directionalMultipliers; - array>::Resize(args.x.tableData.points, ra::ARB_LUT_CAPACITY); - array>::Resize(args.y.tableData.points, ra::ARB_LUT_CAPACITY); - } + [JsonProperty("Degrees of rotation")] + double rotation; - [OnSerializing] - void OnSerializingMethod(StreamingContext context) - { - array>::Resize(args.x.tableData.points, args.x.tableData.length); - array>::Resize(args.y.tableData.points, args.y.tableData.length); - } + [JsonProperty("Degrees of angle snapping")] + double snap; - [OnSerialized] - void OnSerializedMethod(StreamingContext context) + Profile(ra::profile& args) { - array>::Resize(args.x.tableData.points, ra::ARB_LUT_CAPACITY); - array>::Resize(args.y.tableData.points, ra::ARB_LUT_CAPACITY); + Marshal::PtrToStructure(IntPtr(&args), this); } + Profile() : + Profile(default_driver_settings.prof) {} }; [JsonObject(ItemRequired = Required::Always)] -public ref struct LutBase -{ - [JsonConverter(Converters::StringEnumConverter::typeid)] - enum class Mode - { - logarithmic, linear - } mode; - - virtual void SetArgs(AccelArgs%) {} - virtual void SetData(ra::accel_union&) {} -}; - +[StructLayout(LayoutKind::Sequential)] +public value struct DeviceConfig { + [MarshalAs(UnmanagedType::U1)] + bool disable; -[JsonObject(ItemRequired = Required::Always)] -public ref struct SpacedLut abstract : public LutBase -{ - [JsonProperty("Whether points affect velocity (true) or sensitivity (false)")] - bool transfer; + [MarshalAs(UnmanagedType::U1)] + [JsonProperty(Required = Required::Default)] + bool setExtraInfo; - double start; - double stop; - array^ data; + [JsonProperty("DPI (normalizes sens to 1000dpi and converts input speed unit: counts/ms -> in/s)")] + int dpi; - void SetArgsBase(AccelArgs% args) - { - args.spacedTableArgs.transfer = transfer; - args.spacedTableArgs.start = start; - args.spacedTableArgs.stop = stop; - } + [JsonProperty("Polling rate Hz (keep at 0 for automatic adjustment)")] + int pollingRate; + + [ComponentModel::DefaultValue(ra::DEFAULT_TIME_MIN)] + [JsonProperty(Required = Required::Default)] + double minimumTime; - void SetDataBase(ra::accel_union& accel) - { - if (size_t(data->LongLength) > ra::SPACED_LUT_CAPACITY) { - throw gcnew InteropException("data is too large"); - } - } -}; + [ComponentModel::DefaultValue(ra::DEFAULT_TIME_MAX)] + [JsonProperty(Required = Required::Default)] + double maximumTime; -[JsonObject(ItemRequired = Required::Always)] -public ref struct LinearLut sealed : public SpacedLut -{ - LinearLut() + bool ShouldSerializesetExtraInfo() { + return setExtraInfo == true; } - LinearLut(const ra::linear_lut& table) + bool ShouldSerializeminimumTime() { - mode = Mode::linear; - transfer = table.transfer; - start = table.range.start; - stop = table.range.stop; - data = gcnew array(table.range.num); - - pin_ptr pdata = &data[0]; - std::memcpy(pdata, &table.data, sizeof(float) * data->Length); + return minimumTime != ra::DEFAULT_TIME_MIN; } - virtual void SetArgs(AccelArgs% args) override + bool ShouldSerializemaximumTime() { - SetArgsBase(args); - args.spacedTableArgs.num = data->Length; - args.spacedTableArgs.mode = SpacedTableMode::linear; + return maximumTime != ra::DEFAULT_TIME_MAX; } - virtual void SetData(ra::accel_union& accel) override + void Init(const ra::device_config& cfg) { - SetDataBase(accel); - pin_ptr pdata = &data[0]; - std::memcpy(&accel.lin_lut.data, pdata, sizeof(float) * data->Length); + disable = cfg.disable; + setExtraInfo = cfg.set_extra_info; + dpi = cfg.dpi; + pollingRate = cfg.polling_rate; + minimumTime = cfg.clamp.min; + maximumTime = cfg.clamp.max; } }; [JsonObject(ItemRequired = Required::Always)] -public ref struct BinLogLut sealed : public SpacedLut +[StructLayout(LayoutKind::Sequential, CharSet = CharSet::Unicode)] +public ref struct DeviceSettings { - short num; + [MarshalAs(UnmanagedType::ByValTStr, SizeConst = ra::MAX_NAME_LEN)] + String^ name; - BinLogLut() - { - } + [MarshalAs(UnmanagedType::ByValTStr, SizeConst = ra::MAX_NAME_LEN)] + String^ profile; - 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(1 + num * (int(stop) - int(start))); + [MarshalAs(UnmanagedType::ByValTStr, SizeConst = ra::MAX_DEV_ID_LEN)] + String^ id; - pin_ptr pdata = &data[0]; - std::memcpy(pdata, &table.data, sizeof(float) * data->Length); - } + DeviceConfig config; - virtual void SetArgs(AccelArgs% args) override + DeviceSettings(ra::device_settings& args) { - SetArgsBase(args); - args.spacedTableArgs.num = num; - args.spacedTableArgs.mode = SpacedTableMode::binlog; + Marshal::PtrToStructure(IntPtr(&args), this); } - 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"); - } - - pin_ptr pdata = &data[0]; - std::memcpy(&accel.log_lut.data, pdata, sizeof(float) * data->Length); - } + DeviceSettings() : + DeviceSettings(default_device_settings) {} }; -public ref struct RaConvert { - static DriverSettings^ Settings(String^ json) - { - return NonNullable(json); - } +public ref class ProfileErrors +{ + List^ tmp; + bool single; - 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); - } + delegate void MsgHandler(const char*); - static LutBase^ Table(String^ json) + void Add(const char* msg) { - JObject^ jObject = JObject::Parse(json); - - if ((Object^)jObject == nullptr) { - throw gcnew JsonException("bad json"); - } - - LutBase^ base = NonNullable(jObject); - - switch (base->mode) { - case LutBase::Mode::logarithmic: - return NonNullable(jObject); - case LutBase::Mode::linear: - return NonNullable(jObject); - default: - throw gcnew NotImplementedException(); - } + tmp->Add(gcnew String(msg)); } - static String^ Table(LutBase^ lut) +public: + ref struct SingleProfileErrors { - auto serializerSettings = gcnew JsonSerializerSettings(); - return JsonConvert::SerializeObject( - lut, lut->GetType(), Formatting::Indented, serializerSettings); + Profile^ prof; + array^ messages; + int lastX; + int lastY; }; - generic - static T NonNullable(String^ json) + List^ list; + + ProfileErrors(List^ profiles) { - T obj = JsonConvert::DeserializeObject(json); - if (obj == nullptr) throw gcnew JsonException("invalid JSON"); - return obj; + single = profiles->Count == 1; + list = gcnew List(); + tmp = gcnew List(); + MsgHandler^ del = gcnew MsgHandler(this, &ProfileErrors::Add); + GCHandle gch = GCHandle::Alloc(del); + auto fp = static_cast( + Marshal::GetFunctionPointerForDelegate(del).ToPointer()); + ra::profile* native_ptr = new ra::profile(); + + for each (auto prof in profiles) { + Marshal::StructureToPtr(prof, IntPtr(native_ptr), false); + auto [last_x, last_y, _] = ra::valid(*native_ptr, fp); + + if (tmp->Count != 0) { + auto singleErrors = gcnew SingleProfileErrors(); + singleErrors->messages = tmp->ToArray(); + singleErrors->lastX = last_x; + singleErrors->lastY = last_y; + singleErrors->prof = prof; + list->Add(singleErrors); + tmp->Clear(); + } + } + + tmp = nullptr; + gch.Free(); + delete native_ptr; } - generic - static T NonNullable(JObject^ jObject) + bool Empty() { - T obj = jObject->ToObject(); - if (obj == nullptr) throw gcnew JsonException("invalid JSON"); - return obj; + return list->Count == 0; } -}; -public ref struct ExtendedSettings { - DriverSettings^ baseSettings; - Vec2 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) + virtual String^ ToString() override { - if (settingsJson) { - baseSettings = RaConvert::Settings(settingsJson); - } - else { - baseSettings = gcnew DriverSettings(); - } - - if (xTableJson || yTableJson) { - baseSettings->combineMagnitudes = !byComponent; - } + Text::StringBuilder^ sb = gcnew Text::StringBuilder(); - if (xTableJson) { - tables.x = RaConvert::Table(xTableJson); - tables.x->SetArgs(baseSettings->args.x); - } + for each (auto elem in list) { + if (!single) { + sb->AppendFormat("profile: {0}\n", elem->prof->name); + } - if (yTableJson) { - if (Object::ReferenceEquals(yTableJson, xTableJson)) { - tables.y = tables.x; + auto msgs = elem->messages; + if (elem->prof->combineMagnitudes) { + for (int i = 0; i < elem->lastX; i++) { + sb->AppendFormat("\t{0}\n", msgs[i]); + } } else { - tables.y = RaConvert::Table(yTableJson); + for (int i = 0; i < elem->lastX; i++) { + sb->AppendFormat("\tx: {0}\n", msgs[i]); + } + for (int i = elem->lastX; i < elem->lastY; i++) { + sb->AppendFormat("\ty: {0}\n", msgs[i]); + } } - tables.y->SetArgs(baseSettings->args.y); + for (int i = elem->lastY; i < msgs->Length; i++) { + sb->AppendFormat("\t{0}\n", msgs[i]); + } } - } + return sb->ToString(); + } }; -public ref class SettingsErrors +public ref class DeviceErrors { -public: - - List^ list; - int lastX; - int lastY; + List^ tmp; + bool single; delegate void MsgHandler(const char*); void Add(const char* msg) { - list->Add(gcnew String(msg)); + tmp->Add(gcnew String(msg)); } - SettingsErrors(ExtendedSettings^ settings) : - SettingsErrors(settings->baseSettings) {} +public: + ref struct SingleDeviceErrors + { + DeviceSettings^ settings; + array^ messages; + }; + + List^ list; - SettingsErrors(DriverSettings^ settings) + DeviceErrors(List^ devSettings) { - MsgHandler^ del = gcnew MsgHandler(this, &SettingsErrors::Add); + single = devSettings->Count == 1; + list = gcnew List(); + tmp = gcnew List(); + MsgHandler^ del = gcnew MsgHandler(this, &DeviceErrors::Add); GCHandle gch = GCHandle::Alloc(del); auto fp = static_cast( Marshal::GetFunctionPointerForDelegate(del).ToPointer()); + ra::device_settings* native_ptr = new ra::device_settings(); + + for each (auto dev in devSettings) { + Marshal::StructureToPtr(dev, IntPtr(native_ptr), false); + ra::valid(*native_ptr, fp); + + if (tmp->Count != 0) { + auto singleErrors = gcnew SingleDeviceErrors(); + singleErrors->messages = tmp->ToArray(); + singleErrors->settings = dev; + list->Add(singleErrors); + tmp->Clear(); + } + } - ra::settings* args_ptr = new ra::settings(); - Marshal::StructureToPtr(settings, (IntPtr)args_ptr, false); - - list = gcnew List(); - auto [last_x, last_y, _] = ra::valid(*args_ptr, fp); - lastX = last_x; - lastY = last_y; - + tmp = nullptr; gch.Free(); - delete args_ptr; + delete native_ptr; } bool Empty() @@ -503,36 +376,52 @@ public: { Text::StringBuilder^ sb = gcnew Text::StringBuilder(); - for each (auto s in list->GetRange(0, lastX)) - { - sb->AppendFormat("x: {0}\n", s); - } - for each (auto s in list->GetRange(lastX, lastY - lastX)) - { - sb->AppendFormat("y: {0}\n", s); - } - for each (auto s in list->GetRange(lastY, list->Count - lastY)) - { - sb->AppendLine(s); + for each (auto elem in list) { + if (!single) { + sb->AppendFormat("device: {0}\n", elem->settings->id); + if (!String::IsNullOrWhiteSpace(elem->settings->name)) { + sb->AppendFormat(" name: {0}\n", elem->settings->name); + } + } + + for each (auto msg in elem->messages) { + sb->AppendFormat("\tx: {0}\n", msg); + } } return sb->ToString(); } }; -struct instance_t { - ra::io_t data; - vec2 inv; +struct accel_instance_t { + ra::modifier mod; + ra::driver_settings settings; + + accel_instance_t() = default; + + accel_instance_t(ra::driver_settings& args) : + settings(args), + mod(args) {} + + void init(Profile^ args) + { + Marshal::StructureToPtr(args, IntPtr(&settings.prof), false); + ra::init_data(settings); + mod = { settings }; + } }; public ref class ManagedAccel { - instance_t* const instance = new instance_t(); - + accel_instance_t* const instance = new accel_instance_t(); public: + ManagedAccel() {} - ManagedAccel(ExtendedSettings^ settings) + ManagedAccel(ra::driver_settings& settings) : + instance(new accel_instance_t(settings)) {} + + ManagedAccel(Profile^ settings) { Settings = settings; } @@ -547,95 +436,266 @@ public: delete instance; } - Tuple^ Accelerate(int x, int y, double time) + Tuple^ Accelerate(int x, int y, double dpi_factor, double time) { vec2d in_out_vec = { (double)x, (double)y }; - instance->data.mod.modify(in_out_vec, instance->inv, time); + instance->mod.modify(in_out_vec, instance->settings, dpi_factor, time); return gcnew Tuple(in_out_vec.x, in_out_vec.y); } + property Profile^ Settings + { + Profile^ get() + { + return gcnew Profile(instance->settings.prof); + } + + void set(Profile^ val) + { + instance->init(val); + } + + } + + ra::driver_settings GetSettings() + { + return instance->settings; + } + +}; + + +[JsonObject(ItemRequired = Required::Always)] +public ref class DriverConfig { +public: + literal double WriteDelayMs = ra::WRITE_DELAY; + literal int MaxProfiles = ra::DRIVER_CAPACITY; + literal int MaxDevices = ra::DEVICE_CAPACITY; + literal String^ Key = "Driver settings"; + + String^ version = RA_VER_STRING; + + DeviceConfig defaultDeviceConfig; + + List^ profiles; + + [NonSerialized] + List^ accels; + + List^ devices; + void Activate() { + ra::io_t* data = static_cast(malloc(sizeof(ra::io_t))); + + if (!data) throw gcnew Exception("bad alloc"); + + data->default_dev_cfg.disable = defaultDeviceConfig.disable; + data->default_dev_cfg.set_extra_info = defaultDeviceConfig.setExtraInfo; + data->default_dev_cfg.dpi = defaultDeviceConfig.dpi; + data->default_dev_cfg.polling_rate = defaultDeviceConfig.pollingRate; + data->default_dev_cfg.clamp.min = defaultDeviceConfig.minimumTime; + data->default_dev_cfg.clamp.max = defaultDeviceConfig.maximumTime; + + data->driver_data_size = profiles->Count; + data->device_data_size = devices->Count; + + for (auto i = 0; i < profiles->Count; i++) { + auto& drv_settings = data->driver_data[i]; + drv_settings = accels[i]->GetSettings(); + } + + for (auto i = 0; i < devices->Count; i++) { + auto& dev_settings = data->device_data[i]; + Marshal::StructureToPtr(devices[i], IntPtr(&dev_settings), false); + } + try { - ra::write(instance->data); + ra::write(*data); + free(data); } catch (const ra::error& e) { + free(data); throw gcnew InteropException(e); } } - property ExtendedSettings^ Settings + // returns null or a joined list of error messages + String^ Errors() { - 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; + Text::StringBuilder^ sb = gcnew Text::StringBuilder(); + + if (profiles->Count > MaxProfiles) { + sb->AppendFormat("Number of profiles ({0}) exceeds max ({1})\n", profiles->Count, MaxProfiles); } - 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); + if (devices->Count > MaxDevices) { + sb->AppendFormat("Number of devices ({0}) exceeds max ({1})\n", devices->Count, MaxDevices); + } - if (val->tables.x) { - val->tables.x->SetData(instance->data.mod.accel.x); - } + ProfileErrors^ profErrors = gcnew ProfileErrors(profiles); + if (!profErrors->Empty()) { + sb->Append(profErrors->ToString()); + } + + DeviceSettings^ defaultDev = gcnew DeviceSettings(); + defaultDev->config = defaultDeviceConfig; + defaultDev->id = "Default"; + devices->Add(defaultDev); - if (val->tables.y) { - val->tables.y->SetData(instance->data.mod.accel.y); - } + DeviceErrors^ devErrors = gcnew DeviceErrors(devices); + if (!devErrors->Empty()) { + sb->Append(profErrors->ToString()); } + devices->RemoveAt(devices->Count - 1); + + if (sb->Length == 0) { + return nullptr; + } + else { + return sb->ToString(); + } } - static ManagedAccel^ GetActive() + JObject^ ToJObject() { - try { - auto active = gcnew ManagedAccel(); - ra::read(active->instance->data); - active->instance->inv = ra::invokers(active->instance->data.args); - return active; + auto dataQueue = gcnew Queue^>(); + auto empty = Array::Empty(); + + for each (auto prof in profiles) { + if (prof->argsX.mode == AccelMode::lut) { + // data->Length is fixed for interop, + // temporary resize avoids serializing a bunch of zeros + Array::Resize(prof->argsX.data, prof->argsX.length); + } + else { + // table data may be used internally in any mode, + // so hide it when it's not needed for deserialization + dataQueue->Enqueue(prof->argsX.data); + prof->argsX.data = empty; + } + + if (prof->argsY.mode == AccelMode::lut) { + Array::Resize(prof->argsY.data, prof->argsY.length); + } + else { + dataQueue->Enqueue(prof->argsY.data); + prof->argsY.data = empty; + } } - catch (const ra::error& e) { - throw gcnew InteropException(e); + + JObject^ jObject = JObject::FromObject(this); + String^ capModes = String::Join(" | ", Enum::GetNames(ClassicCapMode::typeid)); + String^ accelModes = String::Join(" | ", Enum::GetNames(AccelMode::typeid)); + jObject->AddFirst(gcnew JProperty("### Cap modes (applies to classic only) ###", capModes)); + jObject->AddFirst(gcnew JProperty("### Accel modes ###", accelModes)); + + for each (auto prof in profiles) { + if (prof->argsX.mode == AccelMode::lut) { + Array::Resize(prof->argsX.data, ra::LUT_RAW_DATA_CAPACITY); + } + else { + prof->argsX.data = dataQueue->Dequeue(); + } + + if (prof->argsY.mode == AccelMode::lut) { + Array::Resize(prof->argsY.data, ra::LUT_RAW_DATA_CAPACITY); + } + else { + prof->argsY.data = dataQueue->Dequeue(); + } } + + return jObject; } -private: - LutBase^ extract(ra::spaced_lut_mode mode, ra::accel_union& au) + String^ ToJSON() { - 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(); - } + return ToJObject()->ToString(); } -}; -public ref struct VersionHelper -{ - literal String^ VersionString = RA_VER_STRING; + // returns (config, null) or (null, error message) + static Tuple^ Convert(String^ json) + { + auto jss = gcnew JsonSerializerSettings(); + jss->DefaultValueHandling = DefaultValueHandling::Populate; + auto cfg = JsonConvert::DeserializeObject(json, jss); + if (cfg == nullptr) throw gcnew JsonException("invalid JSON"); - static Version^ ValidOrThrow() + auto message = cfg->Errors(); + if (message != nullptr) { + return gcnew Tuple(nullptr, message); + } + else { + cfg->accels = gcnew List(); + + if (cfg->profiles->Count == 0) { + cfg->profiles->Add(gcnew Profile()); + } + + for each (auto prof in cfg->profiles) { + cfg->accels->Add(gcnew ManagedAccel(prof)); + } + return gcnew Tuple(cfg, nullptr); + } + } + + static DriverConfig^ GetActive() { + ra::io_t* data = static_cast(malloc(sizeof(ra::io_t))); + + if (!data) throw gcnew Exception("io_t alloc failed"); + try { - ra::version_t v = ra::valid_version_or_throw(); - return gcnew Version(v.major, v.minor, v.patch, 0); + ra::read(*data); } catch (const ra::error& e) { + free(data); throw gcnew InteropException(e); + } + + auto cfg = gcnew DriverConfig(); + cfg->profiles = gcnew List(); + cfg->accels = gcnew List(); + cfg->devices = gcnew List(); + + for (auto i = 0u; i < data->driver_data_size; i++) { + auto& drv_settings = data->driver_data[i]; + cfg->profiles->Add(gcnew Profile(drv_settings.prof)); + cfg->accels->Add(gcnew ManagedAccel(drv_settings)); } + + for (auto i = 0u; i < data->device_data_size; i++) { + auto& dev_settings = data->device_data[i]; + cfg->devices->Add(gcnew DeviceSettings(dev_settings)); + } + + cfg->defaultDeviceConfig.Init(data->default_dev_cfg); + + free(data); + return cfg; + } + + static DriverConfig^ GetDefault() + { + auto cfg = gcnew DriverConfig(); + cfg->profiles = gcnew List(); + cfg->accels = gcnew List(); + cfg->devices = gcnew List(); + + cfg->profiles->Add(gcnew Profile()); + cfg->accels->Add(gcnew ManagedAccel(default_driver_settings)); + cfg->defaultDeviceConfig.Init(default_device_settings.config); + return cfg; } + +private: + DriverConfig() {} }; + diff --git a/wrapper/wrapper.vcxproj b/wrapper/wrapper.vcxproj index 5d58614..256b978 100644 --- a/wrapper/wrapper.vcxproj +++ b/wrapper/wrapper.vcxproj @@ -60,7 +60,8 @@ Fast - User32.lib; + + $(SolutionDir)/common; @@ -74,7 +75,8 @@ Fast - User32.lib; + + copy /Y "$(TargetPath)" "$(SolutionDir)signed\$(TargetFileName)" & @@ -98,6 +100,7 @@ copy /Y "$(TargetDir)Newtonsoft.Json.dll" "$(SolutionDir)signed\Newtonsoft.Json. ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll + -- cgit v1.2.3 From 8680805b267bf5280b8f446ed33ef07981ea5475 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Mon, 6 Sep 2021 19:11:47 -0400 Subject: make profile count dynamic (unlimited) --- wrapper/wrapper.cpp | 101 +++++++++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 44 deletions(-) (limited to 'wrapper') diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp index fba66fa..83804a2 100644 --- a/wrapper/wrapper.cpp +++ b/wrapper/wrapper.cpp @@ -462,7 +462,7 @@ public: } - ra::driver_settings GetSettings() + ra::driver_settings NativeSettings() { return instance->settings; } @@ -474,8 +474,6 @@ public: public ref class DriverConfig { public: literal double WriteDelayMs = ra::WRITE_DELAY; - literal int MaxProfiles = ra::DRIVER_CAPACITY; - literal int MaxDevices = ra::DEVICE_CAPACITY; literal String^ Key = "Driver settings"; String^ version = RA_VER_STRING; @@ -491,36 +489,56 @@ public: void Activate() { - ra::io_t* data = static_cast(malloc(sizeof(ra::io_t))); + if (accels->Count != profiles->Count) { + throw gcnew Exception("Profile count does not match ManagedAccel"); + } - if (!data) throw gcnew Exception("bad alloc"); - - data->default_dev_cfg.disable = defaultDeviceConfig.disable; - data->default_dev_cfg.set_extra_info = defaultDeviceConfig.setExtraInfo; - data->default_dev_cfg.dpi = defaultDeviceConfig.dpi; - data->default_dev_cfg.polling_rate = defaultDeviceConfig.pollingRate; - data->default_dev_cfg.clamp.min = defaultDeviceConfig.minimumTime; - data->default_dev_cfg.clamp.max = defaultDeviceConfig.maximumTime; + std::byte* buffer; - data->driver_data_size = profiles->Count; - data->device_data_size = devices->Count; + auto driver_data_bytes = accels->Count * sizeof(ra::driver_settings); + auto device_data_bytes = devices->Count * sizeof(ra::device_settings); - for (auto i = 0; i < profiles->Count; i++) { - auto& drv_settings = data->driver_data[i]; - drv_settings = accels[i]->GetSettings(); + try { + buffer = new std::byte[sizeof(ra::io_base) + driver_data_bytes + device_data_bytes]; + } + catch (const std::exception& e) { + throw gcnew InteropException(e); } + auto* byte_ptr = buffer; + + auto* base_data = reinterpret_cast(byte_ptr); + base_data->default_dev_cfg.disable = defaultDeviceConfig.disable; + base_data->default_dev_cfg.set_extra_info = defaultDeviceConfig.setExtraInfo; + base_data->default_dev_cfg.dpi = defaultDeviceConfig.dpi; + base_data->default_dev_cfg.polling_rate = defaultDeviceConfig.pollingRate; + base_data->default_dev_cfg.clamp.min = defaultDeviceConfig.minimumTime; + base_data->default_dev_cfg.clamp.max = defaultDeviceConfig.maximumTime; + base_data->driver_data_size = accels->Count; + base_data->device_data_size = devices->Count; + + byte_ptr += sizeof(ra::io_base); + + auto* driver_data = reinterpret_cast(byte_ptr); + for (auto i = 0; i < accels->Count; i++) { + auto& drv_settings = driver_data[i]; + drv_settings = accels[i]->NativeSettings(); + } + + byte_ptr += driver_data_bytes; + + auto* device_data = reinterpret_cast(byte_ptr); for (auto i = 0; i < devices->Count; i++) { - auto& dev_settings = data->device_data[i]; + auto& dev_settings = device_data[i]; Marshal::StructureToPtr(devices[i], IntPtr(&dev_settings), false); } try { - ra::write(*data); - free(data); + ra::write(buffer); + delete[] buffer; } - catch (const ra::error& e) { - free(data); + catch (const std::exception& e) { + delete[] buffer; throw gcnew InteropException(e); } } @@ -530,14 +548,6 @@ public: { Text::StringBuilder^ sb = gcnew Text::StringBuilder(); - if (profiles->Count > MaxProfiles) { - sb->AppendFormat("Number of profiles ({0}) exceeds max ({1})\n", profiles->Count, MaxProfiles); - } - - if (devices->Count > MaxDevices) { - sb->AppendFormat("Number of devices ({0}) exceeds max ({1})\n", devices->Count, MaxDevices); - } - ProfileErrors^ profErrors = gcnew ProfileErrors(profiles); if (!profErrors->Empty()) { sb->Append(profErrors->ToString()); @@ -648,15 +658,11 @@ public: static DriverConfig^ GetActive() { - ra::io_t* data = static_cast(malloc(sizeof(ra::io_t))); - - if (!data) throw gcnew Exception("io_t alloc failed"); - + std::unique_ptr bytes; try { - ra::read(*data); + bytes = ra::read(); } - catch (const ra::error& e) { - free(data); + catch (const std::exception& e) { throw gcnew InteropException(e); } @@ -665,20 +671,27 @@ public: cfg->accels = gcnew List(); cfg->devices = gcnew List(); - for (auto i = 0u; i < data->driver_data_size; i++) { - auto& drv_settings = data->driver_data[i]; + auto* byte_ptr = bytes.get(); + ra::io_base* base_data = reinterpret_cast(byte_ptr); + cfg->defaultDeviceConfig.Init(base_data->default_dev_cfg); + + byte_ptr += sizeof(ra::io_base); + + ra::driver_settings* driver_data = reinterpret_cast(byte_ptr); + for (auto i = 0u; i < base_data->driver_data_size; i++) { + auto& drv_settings = driver_data[i]; cfg->profiles->Add(gcnew Profile(drv_settings.prof)); cfg->accels->Add(gcnew ManagedAccel(drv_settings)); } - for (auto i = 0u; i < data->device_data_size; i++) { - auto& dev_settings = data->device_data[i]; + byte_ptr += base_data->driver_data_size * sizeof(ra::driver_settings); + + ra::device_settings* device_data = reinterpret_cast(byte_ptr); + for (auto i = 0u; i < base_data->device_data_size; i++) { + auto& dev_settings = device_data[i]; cfg->devices->Add(gcnew DeviceSettings(dev_settings)); } - cfg->defaultDeviceConfig.Init(data->default_dev_cfg); - - free(data); return cfg; } -- cgit v1.2.3 From a8d48325d5e6fe0466502b865c82317b6f7410a2 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Mon, 6 Sep 2021 23:24:51 -0400 Subject: get grapher building --- wrapper/input.cpp | 7 ++++--- wrapper/wrapper.cpp | 21 ++++++++++++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) (limited to 'wrapper') diff --git a/wrapper/input.cpp b/wrapper/input.cpp index e34af4a..334a0ec 100644 --- a/wrapper/input.cpp +++ b/wrapper/input.cpp @@ -25,11 +25,12 @@ public ref struct MultiHandleDevice { System::String^ id; List^ handles; - // Each element in the list returned has a distinct id + // Returned list represents the current connected raw input devices, + // where each device has a distinct device id // https://docs.microsoft.com/en-us/windows-hardware/drivers/install/device-ids - static List^ GetList() + static IList^ GetList() { - return ListMaker::MakeList(); + return ListMaker::MakeList()->AsReadOnly(); } ref class ListMaker { diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp index 83804a2..6561fd2 100644 --- a/wrapper/wrapper.cpp +++ b/wrapper/wrapper.cpp @@ -695,19 +695,34 @@ public: return cfg; } - static DriverConfig^ GetDefault() + static DriverConfig^ FromProfile(Profile^ prof) { auto cfg = gcnew DriverConfig(); cfg->profiles = gcnew List(); cfg->accels = gcnew List(); cfg->devices = gcnew List(); - cfg->profiles->Add(gcnew Profile()); - cfg->accels->Add(gcnew ManagedAccel(default_driver_settings)); + cfg->profiles->Add(prof); + cfg->accels->Add(gcnew ManagedAccel(prof)); cfg->defaultDeviceConfig.Init(default_device_settings.config); return cfg; } + static DriverConfig^ GetDefault() + { + return FromProfile(gcnew Profile()); + } + + static void Deactivate() + { + try { + ra::reset(); + } + catch (const std::exception& e) { + throw gcnew InteropException(e); + } + } + private: DriverConfig() {} }; -- cgit v1.2.3 From 00d39102b469b459c5803fe1a20e52d8217add08 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Tue, 7 Sep 2021 19:53:00 -0400 Subject: update SettingsManager load active config from driver only when necessary ignore devices that aren't running the active profile (in mousewatcher) --- wrapper/wrapper.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'wrapper') diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp index 6561fd2..5acc0d0 100644 --- a/wrapper/wrapper.cpp +++ b/wrapper/wrapper.cpp @@ -542,6 +542,12 @@ public: throw gcnew InteropException(e); } } + + void SetProfileAt(int index, Profile^ val) + { + profiles[index] = val; + accels[index]->Settings = val; + } // returns null or a joined list of error messages String^ Errors() -- cgit v1.2.3 From 427a94bc4086c67a044ebbaed8bc789b1ed174c9 Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Wed, 8 Sep 2021 04:43:15 -0400 Subject: rename driver_settings found a better one refactor driver/DeviceSetup --- wrapper/wrapper.cpp | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'wrapper') diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp index 5acc0d0..c0b3b22 100644 --- a/wrapper/wrapper.cpp +++ b/wrapper/wrapper.cpp @@ -15,7 +15,7 @@ using namespace Newtonsoft::Json::Linq; namespace ra = rawaccel; -ra::driver_settings default_driver_settings; +ra::modifier_settings default_modifier_settings; ra::device_settings default_device_settings; public ref struct VersionHelper @@ -147,7 +147,7 @@ public ref struct Profile } Profile() : - Profile(default_driver_settings.prof) {} + Profile(default_modifier_settings.prof) {} }; [JsonObject(ItemRequired = Required::Always)] @@ -395,11 +395,11 @@ public: struct accel_instance_t { ra::modifier mod; - ra::driver_settings settings; + ra::modifier_settings settings; accel_instance_t() = default; - accel_instance_t(ra::driver_settings& args) : + accel_instance_t(ra::modifier_settings& args) : settings(args), mod(args) {} @@ -418,7 +418,7 @@ public: ManagedAccel() {} - ManagedAccel(ra::driver_settings& settings) : + ManagedAccel(ra::modifier_settings& settings) : instance(new accel_instance_t(settings)) {} ManagedAccel(Profile^ settings) @@ -462,7 +462,7 @@ public: } - ra::driver_settings NativeSettings() + ra::modifier_settings NativeSettings() { return instance->settings; } @@ -495,11 +495,11 @@ public: std::byte* buffer; - auto driver_data_bytes = accels->Count * sizeof(ra::driver_settings); + auto modifier_data_bytes = accels->Count * sizeof(ra::modifier_settings); auto device_data_bytes = devices->Count * sizeof(ra::device_settings); try { - buffer = new std::byte[sizeof(ra::io_base) + driver_data_bytes + device_data_bytes]; + buffer = new std::byte[sizeof(ra::io_base) + modifier_data_bytes + device_data_bytes]; } catch (const std::exception& e) { throw gcnew InteropException(e); @@ -514,18 +514,18 @@ public: base_data->default_dev_cfg.polling_rate = defaultDeviceConfig.pollingRate; base_data->default_dev_cfg.clamp.min = defaultDeviceConfig.minimumTime; base_data->default_dev_cfg.clamp.max = defaultDeviceConfig.maximumTime; - base_data->driver_data_size = accels->Count; + base_data->modifier_data_size = accels->Count; base_data->device_data_size = devices->Count; byte_ptr += sizeof(ra::io_base); - auto* driver_data = reinterpret_cast(byte_ptr); + auto* modifier_data = reinterpret_cast(byte_ptr); for (auto i = 0; i < accels->Count; i++) { - auto& drv_settings = driver_data[i]; - drv_settings = accels[i]->NativeSettings(); + auto& mod_settings = modifier_data[i]; + mod_settings = accels[i]->NativeSettings(); } - byte_ptr += driver_data_bytes; + byte_ptr += modifier_data_bytes; auto* device_data = reinterpret_cast(byte_ptr); for (auto i = 0; i < devices->Count; i++) { @@ -683,14 +683,14 @@ public: byte_ptr += sizeof(ra::io_base); - ra::driver_settings* driver_data = reinterpret_cast(byte_ptr); - for (auto i = 0u; i < base_data->driver_data_size; i++) { - auto& drv_settings = driver_data[i]; - cfg->profiles->Add(gcnew Profile(drv_settings.prof)); - cfg->accels->Add(gcnew ManagedAccel(drv_settings)); + ra::modifier_settings* modifier_data = reinterpret_cast(byte_ptr); + for (auto i = 0u; i < base_data->modifier_data_size; i++) { + auto& mod_settings = modifier_data[i]; + cfg->profiles->Add(gcnew Profile(mod_settings.prof)); + cfg->accels->Add(gcnew ManagedAccel(mod_settings)); } - byte_ptr += base_data->driver_data_size * sizeof(ra::driver_settings); + byte_ptr += base_data->modifier_data_size * sizeof(ra::modifier_settings); ra::device_settings* device_data = reinterpret_cast(byte_ptr); for (auto i = 0u; i < base_data->device_data_size; i++) { -- cgit v1.2.3 From 4197e030c5cfeda5592816c8028152d9b7b599e0 Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Thu, 16 Sep 2021 13:07:43 -0700 Subject: Remove weight --- wrapper/wrapper.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'wrapper') diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp index c0b3b22..2eefb1b 100644 --- a/wrapper/wrapper.cpp +++ b/wrapper/wrapper.cpp @@ -71,7 +71,6 @@ public value struct AccelArgs double motivity; double exponentClassic; double scale; - double weight; double exponentPower; double limit; double midpoint; -- cgit v1.2.3 From 1fd8881608e4ce6ab21fd78d3ebb42a941cd0e93 Mon Sep 17 00:00:00 2001 From: Jacob Palecki Date: Thu, 16 Sep 2021 18:33:30 -0700 Subject: Add power start from one --- wrapper/wrapper.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'wrapper') diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp index 2eefb1b..9930454 100644 --- a/wrapper/wrapper.cpp +++ b/wrapper/wrapper.cpp @@ -75,6 +75,7 @@ public value struct AccelArgs double limit; double midpoint; double smooth; + bool powerStartFromOne; [JsonProperty("Cap / Jump")] Vec2 cap; -- cgit v1.2.3 From 115030165d539fde5440f6232879c7a076dea2ec Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Sat, 18 Sep 2021 05:20:53 -0400 Subject: generalize power start-from-1 starting output is determined by (gain) offset --- wrapper/wrapper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'wrapper') diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp index 9930454..ce4d298 100644 --- a/wrapper/wrapper.cpp +++ b/wrapper/wrapper.cpp @@ -64,7 +64,8 @@ public value struct AccelArgs [MarshalAs(UnmanagedType::U1)] bool gain; - double offset; + double inputOffset; + double outputOffset; double acceleration; double decayRate; double growthRate; @@ -75,7 +76,6 @@ public value struct AccelArgs double limit; double midpoint; double smooth; - bool powerStartFromOne; [JsonProperty("Cap / Jump")] Vec2 cap; -- cgit v1.2.3 From 94ce1542b03090b81a4250f7f799895c58ab286c Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Sat, 18 Sep 2021 05:34:59 -0400 Subject: rename directional multipliers changes profile layout --- wrapper/wrapper.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'wrapper') diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp index ce4d298..b81e2aa 100644 --- a/wrapper/wrapper.cpp +++ b/wrapper/wrapper.cpp @@ -116,24 +116,19 @@ public ref struct Profile [JsonProperty("Stretches accel range for horizontal vs vertical inputs")] Vec2 rangeXY; - [JsonProperty("Sensitivity multiplier")] - double sensitivity; - - [JsonProperty("Y/X sensitivity ratio (vertical sens multiplier)")] - double yxSensRatio; - [JsonProperty("Whole or horizontal accel parameters")] AccelArgs argsX; [JsonProperty("Vertical accel parameters")] AccelArgs argsY; - [JsonIgnore] - double minimumSpeed; - [JsonProperty("Input Speed Cap")] - double maximumSpeed; - - [JsonProperty("Negative directional multipliers")] - Vec2 directionalMultipliers; + [JsonProperty("Sensitivity multiplier")] + double sensitivity; + [JsonProperty("Y/X sensitivity ratio (vertical sens multiplier)")] + double yxSensRatio; + [JsonProperty("L/R sensitivity ratio (left sens multiplier)")] + double lrSensRatio; + [JsonProperty("U/D sensitivity ratio (up sens multiplier)")] + double udSensRatio; [JsonProperty("Degrees of rotation")] double rotation; @@ -141,6 +136,11 @@ public ref struct Profile [JsonProperty("Degrees of angle snapping")] double snap; + [JsonIgnore] + double minimumSpeed; + [JsonProperty("Input Speed Cap")] + double maximumSpeed; + Profile(ra::profile& args) { Marshal::PtrToStructure(IntPtr(&args), this); -- cgit v1.2.3 From d270a967b606116596114744417a182b3f16218b Mon Sep 17 00:00:00 2001 From: a1xd <68629610+a1xd@users.noreply.github.com> Date: Sat, 18 Sep 2021 05:39:08 -0400 Subject: rename classic_cap_mode --- wrapper/wrapper.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'wrapper') diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp index b81e2aa..a248010 100644 --- a/wrapper/wrapper.cpp +++ b/wrapper/wrapper.cpp @@ -41,7 +41,7 @@ public enum class AccelMode }; [JsonConverter(Converters::StringEnumConverter::typeid)] -public enum class ClassicCapMode { +public enum class CapMode { in_out, input, output }; @@ -81,7 +81,7 @@ public value struct AccelArgs Vec2 cap; [JsonProperty("Cap mode")] - ClassicCapMode capMode; + CapMode capMode; [JsonIgnore] int length; @@ -607,9 +607,9 @@ public: } JObject^ jObject = JObject::FromObject(this); - String^ capModes = String::Join(" | ", Enum::GetNames(ClassicCapMode::typeid)); + String^ capModes = String::Join(" | ", Enum::GetNames(CapMode::typeid)); String^ accelModes = String::Join(" | ", Enum::GetNames(AccelMode::typeid)); - jObject->AddFirst(gcnew JProperty("### Cap modes (applies to classic only) ###", capModes)); + jObject->AddFirst(gcnew JProperty("### Cap modes ###", capModes)); jObject->AddFirst(gcnew JProperty("### Accel modes ###", accelModes)); for each (auto prof in profiles) { -- cgit v1.2.3