diff options
| -rw-r--r-- | common/common.vcxitems | 1 | ||||
| -rw-r--r-- | common/rawaccel-error.hpp | 27 | ||||
| -rw-r--r-- | common/rawaccel-io-def.h | 4 | ||||
| -rw-r--r-- | common/rawaccel-io.hpp | 123 | ||||
| -rw-r--r-- | common/rawaccel-validate.hpp | 168 | ||||
| -rw-r--r-- | common/rawaccel-version.h | 30 | ||||
| -rw-r--r-- | common/utility.hpp | 4 | ||||
| -rw-r--r-- | converter/converter.cpp | 62 | ||||
| -rw-r--r-- | driver/driver.cpp | 2 | ||||
| -rw-r--r-- | driver/driver.h | 3 | ||||
| -rw-r--r-- | grapher/Properties/AssemblyInfo.cs | 4 | ||||
| -rw-r--r-- | wrapper/wrapper.cpp | 463 | ||||
| -rw-r--r-- | wrapper/wrapper.vcxproj | 2 | ||||
| -rw-r--r-- | wrapper/wrapper.vcxproj.filters | 6 | ||||
| -rw-r--r-- | wrapper/wrapper_io.cpp | 40 | ||||
| -rw-r--r-- | wrapper/wrapper_io.hpp | 25 | ||||
| -rw-r--r-- | writer/Program.cs | 38 | ||||
| -rw-r--r-- | writer/Properties/AssemblyInfo.cs | 4 |
18 files changed, 508 insertions, 498 deletions
diff --git a/common/common.vcxitems b/common/common.vcxitems index 4cbe2b7..6d1b861 100644 --- a/common/common.vcxitems +++ b/common/common.vcxitems @@ -26,6 +26,7 @@ <ClInclude Include="$(MSBuildThisFileDirectory)rawaccel-io-def.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)rawaccel-io.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)rawaccel-base.hpp" /> + <ClInclude Include="$(MSBuildThisFileDirectory)rawaccel-validate.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)rawaccel-version.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)rawaccel.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)utility-install.hpp" /> diff --git a/common/rawaccel-error.hpp b/common/rawaccel-error.hpp index cdbe1e5..a9cb7b8 100644 --- a/common/rawaccel-error.hpp +++ b/common/rawaccel-error.hpp @@ -1,11 +1,12 @@ #pragma once -#include <stdexcept> +#include <system_error> +#include <string> namespace rawaccel { - class error : public std::runtime_error { - using std::runtime_error::runtime_error; + class error : public std::runtime_error { + using std::runtime_error::runtime_error; }; class io_error : public error { @@ -14,7 +15,25 @@ namespace rawaccel { class install_error : public io_error { public: - install_error() : io_error("Raw Accel driver is not installed, run installer.exe") {} + install_error() : + io_error("Raw Accel is not installed, run installer.exe") {} + }; + + class sys_error : public io_error { + public: + sys_error(const char* msg, DWORD code = GetLastError()) : + io_error(build_msg(code, msg)) {} + + static std::string build_msg(DWORD code, const char* msg) + { + std::string ret = + std::system_error(code, std::system_category(), msg).what(); + ret += " ("; + ret += std::to_string(code); + ret += ")"; + return ret; + } + }; } diff --git a/common/rawaccel-io-def.h b/common/rawaccel-io-def.h index e169390..399e0f2 100644 --- a/common/rawaccel-io-def.h +++ b/common/rawaccel-io-def.h @@ -1,9 +1,11 @@ #pragma once +#define NOMINMAX + #ifdef _KERNEL_MODE #include <ntddk.h> #else -#include <winioctl.h> +#include <Windows.h> #endif #define RA_DEV_TYPE 0x8888u diff --git a/common/rawaccel-io.hpp b/common/rawaccel-io.hpp index da496fa..a80e254 100644 --- a/common/rawaccel-io.hpp +++ b/common/rawaccel-io.hpp @@ -1,67 +1,84 @@ #pragma once #include "rawaccel-io-def.h" -#include "rawaccel.hpp" #include "rawaccel-version.h" #include "rawaccel-error.hpp" - -#define NOMINMAX -#define WIN32_LEAN_AND_MEAN -#include <Windows.h> - -#include <system_error> +#include "rawaccel.hpp" #pragma warning(push) #pragma warning(disable:4245) // int -> DWORD conversion while passing CTL_CODE namespace rawaccel { - inline void io_control(DWORD code, void* in, DWORD in_size, void* out, DWORD out_size) - { - HANDLE ra_handle = INVALID_HANDLE_VALUE; - - ra_handle = CreateFileW(L"\\\\.\\rawaccel", 0, 0, 0, OPEN_EXISTING, 0, 0); - - if (ra_handle == INVALID_HANDLE_VALUE) { - throw install_error(); - } - - DWORD dummy; - - BOOL success = DeviceIoControl( - ra_handle, - code, - in, - in_size, - out, - out_size, - &dummy, // bytes returned - NULL // overlapped structure - ); - - CloseHandle(ra_handle); - - if (!success) { - throw std::system_error(GetLastError(), std::system_category(), "DeviceIoControl failed"); - } - } - - inline void read(io_t& args) - { - io_control(RA_READ, NULL, 0, &args, sizeof(io_t)); - } - - inline void write(const io_t& args) - { - io_control(RA_WRITE, const_cast<io_t*>(&args), sizeof(io_t), NULL, 0); - } - - inline version_t get_version() - { - version_t ver; - io_control(RA_GET_VERSION, NULL, 0, &ver, sizeof(version_t)); - return ver; - } + inline void io_control(DWORD code, void* in, DWORD in_size, void* out, DWORD out_size) + { + HANDLE ra_handle = INVALID_HANDLE_VALUE; + + ra_handle = CreateFileW(L"\\\\.\\rawaccel", 0, 0, 0, OPEN_EXISTING, 0, 0); + + if (ra_handle == INVALID_HANDLE_VALUE) { + throw install_error(); + } + + DWORD dummy; + + BOOL success = DeviceIoControl( + ra_handle, + code, + in, + in_size, + out, + out_size, + &dummy, // bytes returned + NULL // overlapped structure + ); + + CloseHandle(ra_handle); + + if (!success) { + throw sys_error("DeviceIoControl failed"); + } + } + + inline void read(io_t& args) + { + io_control(RA_READ, NULL, 0, &args, sizeof(io_t)); + } + + inline void write(const io_t& args) + { + io_control(RA_WRITE, const_cast<io_t*>(&args), sizeof(io_t), NULL, 0); + } + + inline version_t get_version() + { + version_t v; + + try { + io_control(RA_GET_VERSION, NULL, 0, &v, sizeof(version_t)); + } + catch (const sys_error&) { + // assume request is not implemented (< 1.3) + v = { 0 }; + } + + return v; + } + + inline version_t valid_version_or_throw() + { + auto v = get_version(); + + if (v < min_driver_version) { + throw error("reinstallation required"); + } + + if (version < v) { + throw error("newer driver is installed"); + } + + return v; + } } diff --git a/common/rawaccel-validate.hpp b/common/rawaccel-validate.hpp new file mode 100644 index 0000000..b9ee2af --- /dev/null +++ b/common/rawaccel-validate.hpp @@ -0,0 +1,168 @@ +#pragma once + +#include "rawaccel-base.hpp" +#include "utility.hpp" + +namespace rawaccel { + + struct valid_ret_t { + int count_x = 0; + int count_y = 0; + int count = 0; + + explicit operator bool() const + { + return count == 0; + } + }; + + template <typename MsgHandler = noop> + valid_ret_t valid(const settings& args, MsgHandler fn = {}) + { + valid_ret_t ret; + + auto error = [&](auto msg) { + ++ret.count; + fn(msg); + }; + + auto check_accel = [&error](const accel_args& args) { + static_assert(LUT_CAPACITY == 1025, "update error msg"); + + const auto& lut_args = args.lut_args; + + if (lut_args.partitions <= 0) { + error("lut partitions"" must be positive"); + } + + if (lut_args.mode == table_mode::linear) { + if (lut_args.start <= 0) { + error("start"" must be positive"); + } + + if (lut_args.stop <= lut_args.start) { + error("stop must be greater than start"); + } + + if (lut_args.num_elements < 2 || + lut_args.num_elements > 1025) { + error("num must be between 2 and 1025"); + } + } + else if (lut_args.mode == table_mode::binlog) { + int istart = static_cast<int>(lut_args.start); + int istop = static_cast<int>(lut_args.stop); + + if (lut_args.start < -99) { + error("start is too small"); + } + else if (lut_args.stop > 99) { + error("stop is too large"); + } + else if (istart != lut_args.start || istop != lut_args.stop) { + error("start and stop must be integers"); + } + else if (istop <= istart) { + error("stop must be greater than start"); + } + else if (lut_args.num_elements <= 0) { + error("num"" must be positive"); + } + else if (((lut_args.stop - lut_args.start) * lut_args.num_elements) >= 1025) { + error("binlog mode requires (num * (stop - start)) < 1025"); + } + } + + if (args.offset < 0) { + error("offset can not be negative"); + } + + if (args.cap <= 0) { + error("cap"" must be positive"); + } + + if (args.accel_motivity <= 0 || + args.accel_natural <= 0 || + args.accel_classic <= 0) { + error("acceleration"" must be positive"); + } + + if (args.motivity <= 1) { + error("motivity must be greater than 1"); + } + + if (args.power <= 1) { + error("power must be greater than 1"); + } + + if (args.scale <= 0) { + error("scale"" must be positive"); + } + + if (args.weight <= 0) { + error("weight"" must be positive"); + } + + if (args.exponent <= 0) { + error("exponent"" must be positive"); + } + + if (args.limit <= 0) { + error("limit"" must be positive"); + } + + if (args.midpoint <= 0) { + error("midpoint"" must be positive"); + } + + if (args.smooth < 0 || args.smooth > 1) { + error("smooth must be between 0 and 1"); + } + + }; + + check_accel(args.argsv.x); + + if (!args.combine_mags) { + ret.count_x = ret.count; + check_accel(args.argsv.y); + ret.count_y = ret.count; + } + + if (args.dpi <= 0) { + error("dpi"" must be positive"); + } + + if (args.speed_cap <= 0) { + error("speed cap"" must be positive"); + } + + if (args.sens.x == 0 || args.sens.y == 0) { + error("sens multiplier is 0"); + } + + if (args.dom_args.domain_weights.x <= 0 || + args.dom_args.domain_weights.y <= 0) { + error("domain weights"" must be positive"); + } + + if (args.dom_args.lp_norm <= 0) { + error("Lp norm can not be negative"); + } + + if (args.dir_multipliers.x < 0 || args.dir_multipliers.y < 0) { + error("directional multipliers can not be negative"); + } + + if (args.range_weights.x <= 0 || args.range_weights.y <= 0) { + error("range weights"" must be positive"); + } + + if (args.time_min <= 0) { + error("minimum time"" must be positive"); + } + + return ret; + } + +} diff --git a/common/rawaccel-version.h b/common/rawaccel-version.h index 40ff2d2..de8644b 100644 --- a/common/rawaccel-version.h +++ b/common/rawaccel-version.h @@ -6,21 +6,31 @@ #define RA_OS "Win7+" -#define M_STR_HELPER(x) #x -#define M_STR(x) M_STR_HELPER(x) +#define RA_M_STR_HELPER(x) #x +#define RA_M_STR(x) RA_M_STR_HELPER(x) -#define RA_VER_STRING M_STR(RA_VER_MAJOR) "." M_STR(RA_VER_MINOR) "." M_STR(RA_VER_PATCH) +#define RA_VER_STRING RA_M_STR(RA_VER_MAJOR) "." RA_M_STR(RA_VER_MINOR) "." RA_M_STR(RA_VER_PATCH) namespace rawaccel { - struct version_t { - int major; - int minor; - int patch; - }; - + struct version_t { + int major; + int minor; + int patch; + }; + + constexpr bool operator<(const version_t& lhs, const version_t& rhs) + { + return (lhs.major != rhs.major) ? + (lhs.major < rhs.major) : + (lhs.minor != rhs.minor) ? + (lhs.minor < rhs.minor) : + (lhs.patch < rhs.patch) ; + } + + inline constexpr version_t version = { RA_VER_MAJOR, RA_VER_MINOR, RA_VER_PATCH }; #ifndef _KERNEL_MODE - inline constexpr version_t min_driver_version = { 1, 4, 0 }; + inline constexpr version_t min_driver_version = { 1, 4, 0 }; #endif } diff --git a/common/utility.hpp b/common/utility.hpp index de90d44..5f5c186 100644 --- a/common/utility.hpp +++ b/common/utility.hpp @@ -81,4 +81,8 @@ namespace rawaccel { return ilogb(x) == 0x400; } + struct noop { + template <typename... Ts> + constexpr void operator()(Ts&&...) const noexcept {} + }; } diff --git a/converter/converter.cpp b/converter/converter.cpp index 230e1be..7b71af3 100644 --- a/converter/converter.cpp +++ b/converter/converter.cpp @@ -1,3 +1,5 @@ +#include <rawaccel-base.hpp> + #include <array> #include <charconv> #include <filesystem> @@ -7,8 +9,6 @@ #include <sstream> #include <string> -#include <rawaccel-settings.h> - using namespace System; using namespace System::Runtime::InteropServices; using namespace Newtonsoft::Json; @@ -108,7 +108,7 @@ auto make_extractor(const ia_settings_t& ia_settings) { }; } -ra::accel_args convert_natural(const ia_settings_t& ia_settings) { +ra::accel_args convert_natural(const ia_settings_t& ia_settings, bool legacy) { auto get = make_extractor(ia_settings); double accel = get("Acceleration").value_or(0); @@ -117,8 +117,13 @@ ra::accel_args convert_natural(const ia_settings_t& ia_settings) { double prescale = get("Pre-ScaleX").value_or(1); ra::accel_args args; + args.limit = 1 + std::abs(cap - sens) / sens; - args.accel = accel * prescale / sens; + args.accel_natural = accel * prescale / sens; + args.offset = get("Offset").value_or(0); + args.mode = ra::accel_mode::natural; + args.legacy = legacy; + return args; } @@ -130,25 +135,16 @@ ra::accel_args convert_quake(const ia_settings_t& ia_settings, bool legacy) { double cap = get("SensitivityCap").value_or(0); double sens = get("Sensitivity").value_or(1); double prescale = get("Pre-ScaleX").value_or(1); - double offset = get("Offset").value_or(0); - - ra::accel_args args; - double powm1 = power - 1; - double rpowm1 = 1 / powm1; - double accel_b = std::pow(accel * prescale, powm1) / sens; - args.accel = std::pow(accel_b, rpowm1); - args.exponent = power; - args.legacy_offset = legacy; - args.offset = offset; - double cap_converted = cap / sens; + ra::accel_args args; - if (legacy || cap_converted <= 1) { - args.scale_cap = cap_converted; - } - else { - args.gain_cap = offset + std::pow(cap_converted - 1, rpowm1) / args.accel; - } + double accel_b = std::pow(accel * prescale, power - 1) / sens; + args.accel_classic = std::pow(accel_b, 1 / (power - 1)); + args.cap = cap / sens; + args.power = power; + args.offset = get("Offset").value_or(0); + args.mode = ra::accel_mode::classic; + args.legacy = legacy; return args; } @@ -168,17 +164,15 @@ bool try_convert(const ia_settings_t& ia_settings) { switch (static_cast<IA_MODES_ENUM>(mode)) { case IA_QL: { - bool legacy = !ask("We recommend trying out our new cap and offset styles.\n" - "Use new cap and offset?"); - ra_settings.modes.x = ra::accel_mode::classic; + bool legacy = !ask("We recommend trying out a new smooth cap style.\n" + "Use new cap style?"); ra_settings.argsv.x = convert_quake(ia_settings, legacy); break; } case IA_NAT: { - bool nat_gain = ask("Raw Accel offers a new mode that you might like more than Natural.\n" + bool legacy = !ask("Raw Accel offers a new mode that you might like more than Natural.\n" "Wanna try it out now?"); - ra_settings.modes.x = nat_gain ? ra::accel_mode::naturalgain : ra::accel_mode::natural; - ra_settings.argsv.x = convert_natural(ia_settings); + ra_settings.argsv.x = convert_natural(ia_settings, legacy); break; } case IA_LOG: { @@ -189,7 +183,7 @@ bool try_convert(const ia_settings_t& ia_settings) { } DriverSettings^ new_settings = Marshal::PtrToStructure<DriverSettings^>((IntPtr)&ra_settings); - auto errors = DriverInterop::GetSettingsErrors(new_settings); + auto errors = gcnew SettingsErrors(new_settings); if (!errors->Empty()) { Console::WriteLine("Bad settings: {0}", errors); @@ -197,7 +191,7 @@ bool try_convert(const ia_settings_t& ia_settings) { } Console::Write("Sending to driver... "); - DriverInterop::Write(new_settings); + (gcnew ManagedAccel(new_settings))->Activate(); Console::WriteLine("done"); Console::Write("Generating settings.json... "); @@ -208,10 +202,6 @@ bool try_convert(const ia_settings_t& ia_settings) { return true; } -public ref struct ASSEMBLY { - static initonly Version^ VERSION = ASSEMBLY::typeid->Assembly->GetName()->Version; -}; - int main() { auto close_prompt = [] { @@ -221,9 +211,9 @@ int main() }; try { - VersionHelper::ValidateAndGetDriverVersion(ASSEMBLY::VERSION); + VersionHelper::ValidOrThrow(); } - catch (VersionException^ ex) { + catch (InteropException^ ex) { Console::WriteLine(ex->Message); close_prompt(); } @@ -239,7 +229,7 @@ int main() entry.path().extension() == IA_PROFILE_EXT) { opt_path = entry; break; - } + } } } diff --git a/driver/driver.cpp b/driver/driver.cpp index 89f09dc..fbc2d3d 100644 --- a/driver/driver.cpp +++ b/driver/driver.cpp @@ -210,7 +210,7 @@ Return Value: DebugPrint(("RetrieveOutputBuffer failed: 0x%x\n", status)); } else { - *reinterpret_cast<ra::version_t*>(buffer) = { RA_VER_MAJOR, RA_VER_MINOR, RA_VER_PATCH }; + *reinterpret_cast<ra::version_t*>(buffer) = ra::version; bytes_out = sizeof(ra::version_t); } break; diff --git a/driver/driver.h b/driver/driver.h index 56742f6..6184a69 100644 --- a/driver/driver.h +++ b/driver/driver.h @@ -1,9 +1,8 @@ #pragma once #include "rawaccel-base.hpp" +#include "rawaccel-io-def.h" -#define NOMINMAX -#include <ntddk.h> #include <kbdmou.h> #include <wdf.h> diff --git a/grapher/Properties/AssemblyInfo.cs b/grapher/Properties/AssemblyInfo.cs index a46d6b3..d381102 100644 --- a/grapher/Properties/AssemblyInfo.cs +++ b/grapher/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion(RawAccelVersion.value)] -[assembly: AssemblyFileVersion(RawAccelVersion.value)] +[assembly: AssemblyVersion(VersionHelper.VersionString)] +[assembly: AssemblyFileVersion(VersionHelper.VersionString)] diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp index 71a8cf6..757972b 100644 --- a/wrapper/wrapper.cpp +++ b/wrapper/wrapper.cpp @@ -1,17 +1,16 @@ #pragma once +#include <rawaccel-io.hpp> +#include <rawaccel-validate.hpp> +#include <utility-rawinput.hpp> + #include <algorithm> #include <type_traits> #include <msclr\marshal_cppstd.h> -#include <rawaccel.hpp> -#include <rawaccel-version.h> -#include <utility-rawinput.hpp> - -#include "wrapper_io.hpp" - using namespace System; using namespace System::Collections::Generic; +using namespace System::IO; using namespace System::Runtime::InteropServices; using namespace System::Reflection; @@ -19,34 +18,39 @@ using namespace Windows::Forms; using namespace Newtonsoft::Json; +namespace ra = rawaccel; + +ra::settings default_settings; + [JsonConverter(Converters::StringEnumConverter::typeid)] public enum class AccelMode { - linear, classic, natural, naturalgain, power, motivity, noaccel + classic, jump, natural, power, motivity, noaccel +}; + +public enum class TableMode +{ + off, binlog, linear }; -[JsonObject(ItemRequired = Required::Always)] [StructLayout(LayoutKind::Sequential)] -public value struct AccelArgs +public value struct TableArgs { - double offset; + [JsonIgnore] + TableMode 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 { @@ -54,7 +58,32 @@ public value struct Vec2 T y; }; -[JsonObject(ItemRequired = Required::Always)] +[StructLayout(LayoutKind::Sequential)] +public value struct AccelArgs +{ + AccelMode mode; + + [MarshalAs(UnmanagedType::U1)] + bool legacy; + + [JsonProperty(Required = Required::Default)] + TableArgs lutArgs; + + double offset; + double cap; + double accelClassic; + double accelNatural; + double accelMotivity; + double motivity; + double power; + double scale; + double weight; + double exponent; + double limit; + double midpoint; + double smooth; +}; + [StructLayout(LayoutKind::Sequential)] public value struct DomainArgs { @@ -66,20 +95,22 @@ 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; + + double speedCap; [JsonProperty("Accel parameters")] Vec2<AccelArgs> args; @@ -87,192 +118,125 @@ 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("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; } DriverSettings() { - domainArgs = { { 1, 1 }, 2 }; - rangeXY = { 1, 1 }; + Marshal::PtrToStructure(IntPtr(&default_settings), this); } -}; - - -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); - }); -} - -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 }; - }); -} - -using error_list_t = Collections::Generic::List<String^>; - -error_list_t^ get_accel_errors(AccelMode mode, AccelArgs^ args) -{ - accel_mode mode_native = (accel_mode)mode; - - auto is_mode = [mode_native](auto... modes) { - return ((mode_native == modes) || ...); - }; - using am = accel_mode; + void ToFile(String^ path) + { + using namespace Newtonsoft::Json::Linq; - 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"); + 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)); } - - if (args->scale <= 0) - error_list->Add("scale must be positive"); - 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"); + static DriverSettings^ FromFile(String^ path) + { + if (!File::Exists(path)) + { + throw gcnew FileNotFoundException( + String::Format("Settings file not found at {0}", path)); + } - if (args->limit <= 1) - error_list->Add("limit must be greater than 1"); + auto settings = JsonConvert::DeserializeObject<DriverSettings^>( + File::ReadAllText(path)); - if (args->midpoint <= 0) - error_list->Add("midpoint must be positive"); + if (settings == nullptr) { + throw gcnew JsonException(String::Format("{0} contains invalid JSON", path)); + } - if (args->offset < 0) - error_list->Add("offset can not be negative"); + return settings; + } +}; - return error_list; -} +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()) {} +}; -error_list_t^ get_other_errors(DriverSettings^ settings) +public ref class SettingsErrors { - auto error_list = gcnew error_list_t(); +public: + List<String^>^ list; + int countX; + int countY; - if (settings->rangeXY.x <= 0 || settings->rangeXY.y <= 0) - { - error_list->Add("range values must be positive"); - } + delegate void MsgHandler(const char*); - if (settings->domainArgs.domainXY.x <= 0 || settings->domainArgs.domainXY.y <= 0) + void Add(const char* msg) { - error_list->Add("domain values must be positive"); + list->Add(msclr::interop::marshal_as<String^>(msg)); } - if (settings->domainArgs.lpNorm <= 0) + SettingsErrors(DriverSettings^ settings) { - error_list->Add("lp norm must be positive"); - } - - return error_list; -} + MsgHandler^ del = gcnew MsgHandler(this, &SettingsErrors::Add); + GCHandle gch = GCHandle::Alloc(del); + auto fp = static_cast<void (*)(const char*)>( + Marshal::GetFunctionPointerForDelegate(del).ToPointer()); -public ref class SettingsErrors -{ -public: - error_list_t^ x; - error_list_t^ y; - error_list_t^ other; + ra::settings args; + Marshal::StructureToPtr(settings, (IntPtr)&args, false); + + list = gcnew List<String^>(); + auto [cx, cy, _] = ra::valid(args, fp); + countX = cx; + countY = cy; + + gch.Free(); + } bool Empty() { - return (x == nullptr || x->Count == 0) && - (y == nullptr || y->Count == 0) && - (other == nullptr || other->Count == 0); + return list->Count == 0; } - virtual String^ ToString() override + virtual String^ ToString() override { - if (x == nullptr) throw; - Text::StringBuilder^ sb = gcnew Text::StringBuilder(); - if (y == nullptr) // assume combineMagnitudes + for each (auto s in list->GetRange(0, countX)) { - for each (String^ str in x) - { - sb->AppendLine(str); - } + sb->AppendFormat("x: {0}\n", s); } - else + for each (auto s in list->GetRange(countX, countY)) { - for each (String^ str in x) - { - sb->AppendFormat("x: {0}\n", str); - } - for each (String^ str in y) - { - sb->AppendFormat("y: {0}\n", str); - } + sb->AppendFormat("y: {0}\n", s); } - - for each (String ^ str in other) + for each (auto s in list->GetRange(countY, list->Count)) { - sb->AppendLine(str); + sb->AppendLine(s); } - + return sb->ToString(); } }; @@ -314,7 +278,7 @@ public ref struct RawInputInterop } catch (const std::exception& e) { - throw gcnew System::Exception(gcnew String(e.what())); + throw gcnew InteropException(e); } } @@ -336,80 +300,32 @@ public ref struct RawInputInterop } catch (const std::exception& e) { - throw gcnew System::Exception(gcnew String(e.what())); + throw gcnew InteropException(e); } } }; -public ref struct DriverInterop +public ref class ManagedAccel { - literal double WriteDelayMs = WRITE_DELAY; - static initonly DriverSettings^ DefaultSettings = get_default(); - - static DriverSettings^ GetActiveSettings() - { - return get_active(); - } - - static void Write(DriverSettings^ args) - { - set_active(args); - } + ra::io_t* const instance = new ra::io_t(); - static DriverSettings^ GetDefaultSettings() - { - return get_default(); - } +public: + ManagedAccel() {}; - static SettingsErrors^ GetSettingsErrors(DriverSettings^ args) + ManagedAccel(DriverSettings^ settings) { - auto errors = gcnew SettingsErrors(); - - errors->x = get_accel_errors(args->modes.x, args->args.x); - - if (!args->combineMagnitudes) { - errors->y = get_accel_errors(args->modes.y, args->args.y); - } - - errors->other = get_other_errors(args); - - return errors; + Settings = settings; } - - - static error_list_t^ GetAccelErrors(AccelMode mode, AccelArgs^ args) - { - return get_accel_errors(mode, args); - } -}; - -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 - -public: - 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) @@ -418,89 +334,64 @@ public: (double)x, (double)y }; - modifier_instance->modify(in_out_vec, time); + + instance->mod.modify(in_out_vec, 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); + } + catch (const ra::error& e) { + throw gcnew InteropException(e); + } } - static ManagedAccel^ GetActiveAccel() + property DriverSettings^ Settings { - settings args; - wrapper_io::readFromDriver(args); + DriverSettings^ get() + { + DriverSettings^ settings = gcnew DriverSettings(); + Marshal::PtrToStructure(IntPtr(&instance->args), settings); + return settings; + } - auto active = gcnew ManagedAccel(); - *active->modifier_instance = { - args - , vec2<si_pair*> { active->lut_x, active->lut_y } - }; - return active; - } -}; + void set(DriverSettings^ val) + { + Marshal::StructureToPtr(val, IntPtr(&instance->args), false); + instance->mod = { instance->args }; + } -public ref struct RawAccelVersion -{ - literal String^ value = RA_VER_STRING; -}; + } -public ref struct VersionException : public Exception -{ -public: - VersionException() {} - VersionException(String^ what) : Exception(what) {} + static ManagedAccel^ GetActive() + { + try { + auto active = gcnew ManagedAccel(); + ra::read(*active->instance); + return active; + } + catch (const ra::error& e) { + throw gcnew InteropException(e); + } + } }; -Version^ convert(rawaccel::version_t v) -{ - return gcnew Version(v.major, v.minor, v.patch, 0); -} - public ref struct VersionHelper { + literal String^ VersionString = RA_VER_STRING; - static Version^ ValidateAndGetDriverVersion(Version^ wrapperTarget) + static Version^ ValidOrThrow() { - Version^ wrapperActual = VersionHelper::typeid->Assembly->GetName()->Version; - - if (wrapperTarget != wrapperActual) { - throw gcnew VersionException("version mismatch, expected wrapper.dll v" + wrapperActual); - } - - version_t drv_ver; - try { - wrapper_io::getDriverVersion(drv_ver); - } - catch (DriverNotInstalledException^ ex) { - throw gcnew VersionException(ex->Message); - } - 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"); - } - - Version^ drv_ver_managed = convert(drv_ver); - - 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)); + 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); } } diff --git a/wrapper/wrapper.vcxproj b/wrapper/wrapper.vcxproj index 721a981..fba03a7 100644 --- a/wrapper/wrapper.vcxproj +++ b/wrapper/wrapper.vcxproj @@ -84,12 +84,10 @@ copy /Y "$(TargetDir)Newtonsoft.Json.dll" "$(SolutionDir)signed\Newtonsoft.Json. </ItemDefinitionGroup> <ItemGroup> <ClInclude Include="resource.h" /> - <ClInclude Include="wrapper_io.hpp" /> </ItemGroup> <ItemGroup> <ClCompile Include="AssemblyInfo.cpp" /> <ClCompile Include="wrapper.cpp" /> - <ClCompile Include="wrapper_io.cpp" /> </ItemGroup> <ItemGroup> <Reference Include="Newtonsoft.Json"> diff --git a/wrapper/wrapper.vcxproj.filters b/wrapper/wrapper.vcxproj.filters index f265d72..96b8e1a 100644 --- a/wrapper/wrapper.vcxproj.filters +++ b/wrapper/wrapper.vcxproj.filters @@ -15,9 +15,6 @@ </Filter> </ItemGroup> <ItemGroup> - <ClInclude Include="wrapper_io.hpp"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="resource.h"> <Filter>Header Files</Filter> </ClInclude> @@ -26,9 +23,6 @@ <ClCompile Include="wrapper.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="wrapper_io.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="AssemblyInfo.cpp"> <Filter>Source Files</Filter> </ClCompile> diff --git a/wrapper/wrapper_io.cpp b/wrapper/wrapper_io.cpp deleted file mode 100644 index 4b77174..0000000 --- a/wrapper/wrapper_io.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include <rawaccel-io.hpp> -#include "wrapper_io.hpp" - -auto with_managed_ex = [](auto fn) { - try - { - fn(); - } - catch (const install_error&) - { - throw gcnew DriverNotInstalledException(); - } - catch (const std::system_error& e) - { - throw gcnew DriverIOException(gcnew String(e.what())); - } -}; - -void wrapper_io::writeToDriver(const settings& args) -{ - with_managed_ex([&] { - write(args); - }); -} - -void wrapper_io::readFromDriver(settings& args) -{ - with_managed_ex([&] { - args = read(); - }); -} - -void wrapper_io::getDriverVersion(version_t& ver) -{ - with_managed_ex([&] { - ver = get_version(); - }); -} diff --git a/wrapper/wrapper_io.hpp b/wrapper/wrapper_io.hpp deleted file mode 100644 index 6b94e46..0000000 --- a/wrapper/wrapper_io.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include <rawaccel-error.hpp> -#include <rawaccel-settings.h> -#include <rawaccel-version.h> - -using namespace rawaccel; -using namespace System; - -struct wrapper_io { - static void writeToDriver(const settings&); - static void readFromDriver(settings&); - static void getDriverVersion(version_t&); -}; - -public ref struct DriverIOException : public IO::IOException { -public: - DriverIOException() {} - DriverIOException(String^ what) : IO::IOException(what) {} -}; - -public ref struct DriverNotInstalledException : public DriverIOException { - DriverNotInstalledException() : - DriverIOException(gcnew String(install_error().what())) {} -}; diff --git a/writer/Program.cs b/writer/Program.cs index 37e384c..d381c16 100644 --- a/writer/Program.cs +++ b/writer/Program.cs @@ -16,27 +16,13 @@ namespace writer MessageBox.Show(msg, "Raw Accel writer"); } - static void Send(JToken settingsToken) - { - var settings = settingsToken.ToObject<DriverSettings>(); - - var errors = DriverInterop.GetSettingsErrors(settings); - if (errors.Empty()) - { - DriverInterop.Write(settings); - return; - } - - Show($"Bad settings:\n\n{errors}"); - } - static void Main(string[] args) { try { - VersionHelper.ValidateAndGetDriverVersion(typeof(Program).Assembly.GetName().Version); + VersionHelper.ValidOrThrow(); } - catch (VersionException e) + catch (InteropException e) { Show(e.Message); return; @@ -48,23 +34,19 @@ namespace writer return; } - if (!File.Exists(args[0])) - { - Show($"Settings file not found at {args[0]}"); - return; - } - try { - var JO = JObject.Parse(File.ReadAllText(args[0])); + var settings = DriverSettings.FromFile(args[0]); + var errors = new SettingsErrors(settings); - if (JO.ContainsKey(DriverSettings.Key)) + if (errors.Empty()) { - Send(JO[DriverSettings.Key]); - return; + new ManagedAccel(settings).Activate(); + } + else + { + Show($"Bad settings:\n\n{errors}"); } - - Send(JO); } catch (JsonException e) { diff --git a/writer/Properties/AssemblyInfo.cs b/writer/Properties/AssemblyInfo.cs index fc6a1ca..7f47c6d 100644 --- a/writer/Properties/AssemblyInfo.cs +++ b/writer/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion(RawAccelVersion.value)] -[assembly: AssemblyFileVersion(RawAccelVersion.value)] +[assembly: AssemblyVersion(VersionHelper.VersionString)] +[assembly: AssemblyFileVersion(VersionHelper.VersionString)]
\ No newline at end of file |