summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authora1xd <[email protected]>2021-09-24 02:04:43 -0400
committerGitHub <[email protected]>2021-09-24 02:04:43 -0400
commit2896b8a09ce42e965705c58593b8738adc454f7f (patch)
tree71e4d0cff60b5a1ad11427d78e1f8c7b775e5690 /common
parentMerge pull request #107 from a1xd/1.5.0-fix (diff)
parentmake note clearer (diff)
downloadrawaccel-dark-mode.tar.xz
rawaccel-dark-mode.zip
Merge pull request #108 from a1xd/1.6r2HEADv1.6.0masterdark-mode
v1.6
Diffstat (limited to 'common')
-rw-r--r--common/accel-classic.hpp135
-rw-r--r--common/accel-invoke.hpp52
-rw-r--r--common/accel-jump.hpp18
-rw-r--r--common/accel-lookup.hpp305
-rw-r--r--common/accel-motivity.hpp81
-rw-r--r--common/accel-natural.hpp19
-rw-r--r--common/accel-noaccel.hpp2
-rw-r--r--common/accel-power.hpp161
-rw-r--r--common/accel-union.hpp119
-rw-r--r--common/common.vcxitems3
-rw-r--r--common/math-vec2.hpp37
-rw-r--r--common/rawaccel-base.hpp94
-rw-r--r--common/rawaccel-io-def.h10
-rw-r--r--common/rawaccel-io.hpp55
-rw-r--r--common/rawaccel-validate.hpp184
-rw-r--r--common/rawaccel-version.h6
-rw-r--r--common/rawaccel.hpp261
-rw-r--r--common/utility-install.hpp23
-rw-r--r--common/utility.hpp15
-rw-r--r--common/vec2.h9
20 files changed, 828 insertions, 761 deletions
diff --git a/common/accel-classic.hpp b/common/accel-classic.hpp
index 4385897..2ca1233 100644
--- a/common/accel-classic.hpp
+++ b/common/accel-classic.hpp
@@ -3,84 +3,142 @@
#include "rawaccel-base.hpp"
#include "utility.hpp"
-#include <math.h>
#include <float.h>
namespace rawaccel {
/// <summary> Struct to hold "classic" (linear raised to power) acceleration implementation. </summary>
struct classic_base {
- double offset;
- double power;
- double accel_raised;
-
- classic_base(const accel_args& args) :
- offset(args.offset),
- power(args.power),
- accel_raised(pow(args.accel_classic, power - 1)) {}
+ double base_fn(double x, double accel_raised, const accel_args& args) const
+ {
+ return accel_raised * pow(x - args.input_offset, args.exponent_classic) / x;
+ }
- double base_fn(double x) const
+ static double base_accel(double x, double y, const accel_args& args)
{
- return accel_raised * pow(x - offset, power) / x;
+ auto power = args.exponent_classic;
+ return pow(x * y * pow(x - args.input_offset, -power), 1 / (power - 1));
}
};
- struct classic_legacy : classic_base {
- double sens_cap = DBL_MAX;
+ template <bool Gain> struct classic;
+
+ template<>
+ struct classic<LEGACY> : classic_base {
+ double accel_raised;
+ double cap = DBL_MAX;
double sign = 1;
- classic_legacy(const accel_args& args) :
- classic_base(args)
+ classic(const accel_args& args)
{
- if (args.cap > 0) {
- sens_cap = args.cap - 1;
+ switch (args.cap_mode) {
+ case cap_mode::io:
+ cap = args.cap.y - 1;
- if (sens_cap < 0) {
- sens_cap = -sens_cap;
+ if (cap < 0) {
+ cap = -cap;
sign = -sign;
}
+
+ {
+ double a = base_accel(args.cap.x, cap, args);
+ accel_raised = pow(a, args.exponent_classic - 1);
+ }
+ break;
+ case cap_mode::in:
+ accel_raised = pow(args.acceleration, args.exponent_classic - 1);
+ if (args.cap.x > 0) {
+ cap = base_fn(args.cap.x, accel_raised, args);
+ }
+ break;
+ case cap_mode::out:
+ default:
+ accel_raised = pow(args.acceleration, args.exponent_classic - 1);
+
+ if (args.cap.y > 0) {
+ cap = args.cap.y - 1;
+
+ if (cap < 0) {
+ cap = -cap;
+ sign = -sign;
+ }
+ }
+
+ break;
}
}
- double operator()(double x) const
+ double operator()(double x, const accel_args& args) const
{
- if (x <= offset) return 1;
- return sign * minsd(base_fn(x), sens_cap) + 1;
- }
+ if (x <= args.input_offset) return 1;
+ return sign * minsd(base_fn(x, accel_raised, args), cap) + 1;
+ }
+
};
- struct classic : classic_base {
- vec2d gain_cap = { DBL_MAX, DBL_MAX };
+ template<>
+ struct classic<GAIN> : classic_base {
+ double accel_raised;
+ vec2d cap = { DBL_MAX, DBL_MAX };
double constant = 0;
double sign = 1;
- classic(const accel_args& args) :
- classic_base(args)
+ classic(const accel_args& args)
{
- if (args.cap > 0) {
- gain_cap.y = args.cap - 1;
+ switch (args.cap_mode) {
+ case cap_mode::io:
+ cap.x = args.cap.x;
+ cap.y = args.cap.y - 1;
- if (gain_cap.y < 0) {
- gain_cap.y = -gain_cap.y;
+ if (cap.y < 0) {
+ cap.y = -cap.y;
sign = -sign;
}
- gain_cap.x = gain_inverse(gain_cap.y, args.accel_classic, power, offset);
- constant = (base_fn(gain_cap.x) - gain_cap.y) * gain_cap.x;
+ {
+ double a = gain_accel(cap.x, cap.y, args.exponent_classic, args.input_offset);
+ accel_raised = pow(a, args.exponent_classic - 1);
+ }
+ constant = (base_fn(cap.x, accel_raised, args) - cap.y) * cap.x;
+ break;
+ case cap_mode::in:
+ accel_raised = pow(args.acceleration, args.exponent_classic - 1);
+ if (args.cap.x > 0) {
+ cap.x = args.cap.x;
+ cap.y = gain(cap.x, args.acceleration, args.exponent_classic, args.input_offset);
+ constant = (base_fn(cap.x, accel_raised, args) - cap.y) * cap.x;
+ }
+ break;
+ case cap_mode::out:
+ default:
+ accel_raised = pow(args.acceleration, args.exponent_classic - 1);
+
+ if (args.cap.y > 0) {
+ cap.y = args.cap.y - 1;
+
+ if (cap.y < 0) {
+ cap.y = -cap.y;
+ sign = -sign;
+ }
+
+ cap.x = gain_inverse(cap.y, args.acceleration, args.exponent_classic, args.input_offset);
+ constant = (base_fn(cap.x, accel_raised, args) - cap.y) * cap.x;
+ }
+ break;
}
}
- double operator()(double x) const
+ double operator()(double x, const accel_args& args) const
{
double output;
- if (x <= offset) return 1;
+ if (x <= args.input_offset) return 1;
- if (x < gain_cap.x) {
- output = base_fn(x);
+ if (x < cap.x) {
+ output = base_fn(x, accel_raised, args);
}
else {
- output = constant / x + gain_cap.y;
+ output = constant / x + cap.y;
}
return sign * output + 1;
@@ -100,6 +158,7 @@ namespace rawaccel {
{
return -pow(y / power, 1 / (power - 1)) / (offset - x);
}
+
};
}
diff --git a/common/accel-invoke.hpp b/common/accel-invoke.hpp
deleted file mode 100644
index f2a95dc..0000000
--- a/common/accel-invoke.hpp
+++ /dev/null
@@ -1,52 +0,0 @@
-#pragma once
-
-#include "accel-union.hpp"
-
-namespace rawaccel {
-
- class accel_invoker {
- using callback_t = double (*)(const accel_union&, double, double);
-
- callback_t cb = &invoke_impl<accel_noaccel>;
-
- template <typename T>
- static double invoke_impl(const accel_union& u, double x, double w)
- {
- return apply_weighted(reinterpret_cast<const T&>(u), x, w);
- }
-
- public:
-
- accel_invoker(const accel_args& args)
- {
- cb = visit_accel([](auto&& arg) {
- using T = remove_ref_t<decltype(arg)>;
-
- if constexpr (is_same_v<T, motivity>) {
- static_assert(sizeof motivity == sizeof binlog_lut);
- return &invoke_impl<binlog_lut>;
- }
- else {
- return &invoke_impl<T>;
- }
-
- }, make_mode(args), accel_union{});
- }
-
- accel_invoker() = default;
-
- double invoke(const accel_union& u, double x, double weight = 1) const
- {
- return (*cb)(u, x, weight);
- }
- };
-
- inline vec2<accel_invoker> invokers(const settings& args)
- {
- return {
- accel_invoker(args.argsv.x),
- accel_invoker(args.argsv.y)
- };
- }
-
-}
diff --git a/common/accel-jump.hpp b/common/accel-jump.hpp
index 95fa461..e3d798e 100644
--- a/common/accel-jump.hpp
+++ b/common/accel-jump.hpp
@@ -5,14 +5,14 @@
namespace rawaccel {
struct jump_base {
- static constexpr double smooth_scale = 2 * PI;
+ static constexpr double smooth_scale = 2 * M_PI;
vec2d step;
double smooth_rate;
// requirements: args.smooth in range [0, 1]
jump_base(const accel_args& args) :
- step({ args.offset, args.cap - 1 })
+ step({ args.cap.x, args.cap.y - 1 })
{
double rate_inverse = args.smooth * step.x;
@@ -43,12 +43,16 @@ namespace rawaccel {
{
return step.y * (x + log(1 + decay(x)) / smooth_rate);
}
+
};
- struct jump_legacy : jump_base {
+ template <bool Gain> struct jump;
+
+ template<>
+ struct jump<LEGACY> : jump_base {
using jump_base::jump_base;
- double operator()(double x) const
+ double operator()(double x, const accel_args&) const
{
if (is_smooth()) return smooth(x) + 1;
else if (x < step.x) return 1;
@@ -56,14 +60,15 @@ namespace rawaccel {
}
};
- struct jump : jump_base {
+ template<>
+ struct jump<GAIN> : jump_base {
double C;
jump(const accel_args& args) :
jump_base(args),
C(-smooth_antideriv(0)) {}
- double operator()(double x) const
+ double operator()(double x, const accel_args&) const
{
if (x <= 0) return 1;
@@ -72,6 +77,7 @@ namespace rawaccel {
if (x < step.x) return 1;
else return 1 + step.y * (x - step.x) / x;
}
+
};
}
diff --git a/common/accel-lookup.hpp b/common/accel-lookup.hpp
index 99f39e9..920df1c 100644
--- a/common/accel-lookup.hpp
+++ b/common/accel-lookup.hpp
@@ -3,31 +3,8 @@
#include "rawaccel-base.hpp"
#include "utility.hpp"
-#include <math.h>
-
namespace rawaccel {
- struct linear_range {
- double start;
- double stop;
- int num;
-
- template <typename Func>
- void for_each(Func fn) const
- {
- double interval = (stop - start) / (num - 1);
- for (int i = 0; i < num; i++) {
- fn(i * interval + start);
- }
- }
-
- int size() const
- {
- return num;
- }
- };
-
-
// represents the range [2^start, 2^stop], with num - 1
// elements linearly spaced between each exponential step
struct fp_rep_range {
@@ -55,252 +32,70 @@ namespace rawaccel {
}
};
- template <typename Lookup>
- struct lut_base {
- enum { capacity = SPACED_LUT_CAPACITY };
- using value_t = float;
-
- template <typename Func>
- void fill(Func fn)
- {
- auto* self = static_cast<Lookup*>(this);
-
- self->range.for_each([&, fn, i = 0](double x) mutable {
- self->data[i++] = static_cast<value_t>(fn(x));
- });
- }
-
- };
-
- struct linear_lut : lut_base<linear_lut> {
- linear_range range;
- bool transfer = false;
- value_t data[capacity] = {};
-
- double operator()(double x) const
- {
- if (x > range.start) {
- double range_dist = range.stop - range.start;
- double idx_f = (x - range.start) * (range.num - 1) / range_dist;
-
- unsigned idx = min(static_cast<int>(idx_f), range.size() - 2);
-
- if (idx < capacity - 1) {
- double y = lerp(data[idx], data[idx + 1], idx_f - idx);
- if (transfer) y /= x;
- return y;
- }
- }
-
- double y = data[0];
- if (transfer) y /= range.start;
- return y;
+ __forceinline
+ constexpr double lerp(double a, double b, double t)
+ {
+ double x = a + t * (b - a);
+ if ((t > 1) == (a < b)) {
+ return maxsd(x, b);
}
+ return minsd(x, b);
+ }
- linear_lut(const spaced_lut_args& args) :
- range({
- args.start,
- args.stop,
- args.num_elements
- }),
- transfer(args.transfer) {}
+ struct lookup {
+ enum { capacity = LUT_POINTS_CAPACITY };
- linear_lut(const accel_args& args) :
- linear_lut(args.spaced_args) {}
- };
+ int size;
+ bool velocity;
- struct binlog_lut : lut_base<binlog_lut> {
- fp_rep_range range;
- double x_start;
- bool transfer = false;
- value_t data[capacity] = {};
+ lookup(const accel_args& args) :
+ size(args.length / 2),
+ velocity(args.gain) {}
- double operator()(double x) const
+ double operator()(double x, const accel_args& args) const
{
- int e = min(ilogb(x), range.stop - 1);
-
- if (e >= range.start) {
- int idx_int_log_part = e - range.start;
- double idx_frac_lin_part = scalbn(x, -e) - 1;
- double idx_f = range.num * (idx_int_log_part + idx_frac_lin_part);
-
- unsigned idx = min(static_cast<int>(idx_f), range.size() - 2);
+ auto* points = reinterpret_cast<const vec2<float>*>(args.data);
+
+ int lo = 0;
+ int hi = size - 2;
+
+ if (x <= 0) return 0;
+
+ if (hi < capacity - 1) {
+
+ while (lo <= hi) {
+ int mid = (lo + hi) / 2;
+ auto p = points[mid];
+
+ if (x < p.x) {
+ hi = mid - 1;
+ }
+ else if (x > p.x) {
+ lo = mid + 1;
+ }
+ else {
+ double y = p.y;
+ if (velocity) y /= x;
+ return y;
+ }
+ }
- if (idx < capacity - 1) {
- double y = lerp(data[idx], data[idx + 1], idx_f - idx);
- if (transfer) y /= x;
+ if (lo > 0) {
+ auto& a = points[lo - 1];
+ auto& b = points[lo];
+ double t = (x - a.x) / (b.x - a.x);
+ double y = lerp(a.y, b.y, t);
+ if (velocity) y /= x;
return y;
}
+
}
- double y = data[0];
- if (transfer) y /= x_start;
+ double y = points[0].y;
+ if (velocity) y /= points[0].x;
return y;
}
-
- binlog_lut(const spaced_lut_args& args) :
- range({
- static_cast<int>(args.start),
- static_cast<int>(args.stop),
- args.num_elements
- }),
- x_start(scalbn(1, range.start)),
- transfer(args.transfer) {}
-
- binlog_lut(const accel_args& args) :
- binlog_lut(args.spaced_args) {}
};
- struct si_pair {
- float slope = 0;
- float intercept = 0;
- };
-
- struct arbitrary_lut_point {
- float applicable_speed = 0;
- si_pair slope_intercept = {};
- };
- struct arbitrary_lut {
- enum { capacity = ARB_LUT_CAPACITY };
-
- fp_rep_range range;
- arbitrary_lut_point data[capacity] = {};
- int log_lookup[capacity] = {};
- double first_point_speed;
- double last_point_speed;
- int last_arbitrary_index;
- int last_log_lookup_index;
- double last_log_lookup_speed;
- double first_log_lookup_speed;
- bool velocity_points;
-
- double operator()(double speed) const
- {
- int index = 0;
- int last_arb_index = last_arbitrary_index;
- int last_log_index = last_log_lookup_index;
-
- if (speed <= 0) return 1;
-
- if (unsigned(last_arb_index) < capacity &&
- unsigned(last_log_index) < capacity &&
- speed > first_point_speed)
- {
- if (speed > last_point_speed)
- {
- index = last_arb_index;
- }
- else if (speed > last_log_lookup_speed)
- {
- int last_log = log_lookup[last_log_index];
- if (unsigned(last_log) >= capacity) return 1;
- index = search_from(last_log, last_arb_index, speed);
- }
- else if (speed < first_log_lookup_speed)
- {
- index = search_from(0, last_arb_index, speed);
- }
- else
- {
- int log_index = get_log_index(speed);
- if (unsigned(log_index) >= capacity) return 1;
- int arbitrary_index = log_lookup[log_index];
- if (arbitrary_index < 0) return 1;
- index = search_from(arbitrary_index, last_arb_index, speed);
- }
-
- }
-
- return apply(index, speed);
- }
-
- int inline get_log_index(double speed) const
- {
- double speed_log = log(speed) - range.start;
- int index = (int)floor(speed_log * range.num);
- return index;
- }
-
- int inline search_from(int index, int last, double speed) const
- {
- do
- {
- index++;
- }
- while (index <= last && data[index].applicable_speed < speed);
-
- return index - 1;
- }
-
- double inline apply(int index, double speed) const
- {
- auto [slope, intercept] = data[index].slope_intercept;
-
- if (velocity_points)
- {
- return slope + intercept / speed;
- }
- else
- {
- return slope * speed + intercept;
- }
- }
-
- void fill(const vec2<float>* points, int length)
- {
- first_point_speed = points[0].x;
- last_arbitrary_index = length - 1;
- // -2 because the last index in the arbitrary array is used for slope-intercept only
- last_point_speed = points[length-2].x;
-
- int start = static_cast<int>(floor(log(first_point_speed)));
- first_log_lookup_speed = exp(start*1.0);
- int end = static_cast<int>(floor(log(last_point_speed)));
- last_log_lookup_speed = exp(end*1.0);
- int num = end > start ? static_cast<int>(capacity / (end - start)) : 1;
- range = fp_rep_range{ start, end, num };
- last_log_lookup_index = end > start ? num * (end - start) - 1 : 0;
-
- vec2<float> current = {0, velocity_points ? 0.0f : 1.0f };
- vec2<float> next;
- int log_index = 0;
- double log_inner_iterator = range.start;
- double log_inner_slice = 1.0 / (range.num * 1.0);
- double log_value = exp(log_inner_iterator);
-
- for (int i = 0; i < length; i++)
- {
- next = points[i];
- double slope = (next.y - current.y) / (next.x - current.x);
- double intercept = next.y - slope * next.x;
- si_pair current_si = {
- static_cast<float>(slope),
- static_cast<float>(intercept)
- };
- arbitrary_lut_point current_lut_point = {
- static_cast<float>(current.x),
- current_si
- };
-
- this->data[i] = current_lut_point;
-
- while (log_value < next.x && log_inner_iterator < end)
- {
- this->log_lookup[log_index] = i;
- log_index++;
- log_inner_iterator += log_inner_slice;
- log_value = exp(log_inner_iterator);
- }
-
- current = next;
- }
- }
-
- arbitrary_lut(const accel_args& args)
- {
- velocity_points = args.arb_args.velocity;
- fill(args.arb_args.data, args.arb_args.length);
- }
- };
}
diff --git a/common/accel-motivity.hpp b/common/accel-motivity.hpp
index 0efe7ea..e9be023 100644
--- a/common/accel-motivity.hpp
+++ b/common/accel-motivity.hpp
@@ -2,43 +2,52 @@
#include "accel-lookup.hpp"
-#include <math.h>
-
namespace rawaccel {
- struct sigmoid {
+ template <bool Gain> struct loglog_sigmoid;
+
+ template <>
+ struct loglog_sigmoid<LEGACY> {
double accel;
double motivity;
double midpoint;
double constant;
- sigmoid(const accel_args& args) :
+ loglog_sigmoid(const accel_args& args) :
accel(exp(args.growth_rate)),
motivity(2 * log(args.motivity)),
midpoint(log(args.midpoint)),
constant(-motivity / 2) {}
- double operator()(double x) const
+ double operator()(double x, const accel_args&) const
{
double denom = exp(accel * (midpoint - log(x))) + 1;
return exp(motivity / denom + constant);
}
+
};
- /// <summary> Struct to hold sigmoid (s-shaped) gain implementation. </summary>
- struct motivity : binlog_lut {
+ template <>
+ struct loglog_sigmoid<GAIN> {
+ enum { capacity = LUT_RAW_DATA_CAPACITY };
- using binlog_lut::operator();
+ bool velocity;
+ fp_rep_range range;
+ double x_start;
- motivity(const accel_args& args) :
- binlog_lut(args)
+ loglog_sigmoid(const accel_args& args)
{
+ init({ -3, 9, 8 }, true);
+
double sum = 0;
double a = 0;
- auto sigmoid_sum = [&, sig = sigmoid(args)](double b) mutable {
- double interval = (b - a) / args.spaced_args.partitions;
- for (int i = 1; i <= args.spaced_args.partitions; i++) {
- sum += sig(a + i * interval) * interval;
+ auto sig = loglog_sigmoid<LEGACY>(args);
+ auto sigmoid_sum = [&](double b) {
+ int partitions = 2;
+
+ double interval = (b - a) / partitions;
+ for (int i = 1; i <= partitions; i++) {
+ sum += sig(a + i * interval, args) * interval;
}
a = b;
return sum;
@@ -46,9 +55,49 @@ namespace rawaccel {
fill([&](double x) {
double y = sigmoid_sum(x);
- if (!this->transfer) y /= x;
+ if (!velocity) y /= x;
return y;
- });
+ }, args, range);
+ }
+
+ double operator()(double x, const accel_args& args) const
+ {
+ auto* data = args.data;
+
+ int e = min(ilogb(x), range.stop - 1);
+
+ if (e >= range.start) {
+ int idx_int_log_part = e - range.start;
+ double idx_frac_lin_part = scalbn(x, -e) - 1;
+ double idx_f = range.num * (idx_int_log_part + idx_frac_lin_part);
+
+ unsigned idx = min(static_cast<int>(idx_f), range.size() - 2);
+
+ if (idx < capacity - 1) {
+ double y = lerp(data[idx], data[idx + 1], idx_f - idx);
+ if (velocity) y /= x;
+ return y;
+ }
+ }
+
+ double y = data[0];
+ if (velocity) y /= x_start;
+ return y;
+ }
+
+ void init(const fp_rep_range& r, bool vel)
+ {
+ velocity = vel;
+ range = r;
+ x_start = scalbn(1, range.start);
+ }
+
+ template <typename Func>
+ static void fill(Func fn, const accel_args& args, const fp_rep_range& range)
+ {
+ range.for_each([&, fn, i = 0](double x) mutable {
+ args.data[i++] = static_cast<float>(fn(x));
+ });
}
};
diff --git a/common/accel-natural.hpp b/common/accel-natural.hpp
index 9f76d1a..9d615a9 100644
--- a/common/accel-natural.hpp
+++ b/common/accel-natural.hpp
@@ -2,8 +2,6 @@
#include "rawaccel-base.hpp"
-#include <math.h>
-
namespace rawaccel {
/// <summary> Struct to hold "natural" (vanishing difference) acceleration implementation. </summary>
@@ -13,16 +11,20 @@ namespace rawaccel {
double limit;
natural_base(const accel_args& args) :
- offset(args.offset),
+ offset(args.input_offset),
limit(args.limit - 1)
{
accel = args.decay_rate / fabs(limit);
}
+
};
- struct natural_legacy : natural_base {
+ template<bool Gain> struct natural;
+
+ template<>
+ struct natural<LEGACY> : natural_base {
- double operator()(double x) const
+ double operator()(double x, const accel_args&) const
{
if (x <= offset) return 1;
@@ -34,10 +36,11 @@ namespace rawaccel {
using natural_base::natural_base;
};
- struct natural : natural_base {
+ template<>
+ struct natural<GAIN> : natural_base {
double constant;
- double operator()(double x) const
+ double operator()(double x, const accel_args&) const
{
if (x <= offset) return 1;
@@ -50,6 +53,6 @@ namespace rawaccel {
natural(const accel_args& args) :
natural_base(args),
constant(-limit / accel) {}
- };
+ };
}
diff --git a/common/accel-noaccel.hpp b/common/accel-noaccel.hpp
index 8d1e758..b307d99 100644
--- a/common/accel-noaccel.hpp
+++ b/common/accel-noaccel.hpp
@@ -10,7 +10,7 @@ namespace rawaccel {
accel_noaccel(const accel_args&) {}
accel_noaccel() = default;
- double operator()(double) const { return 1; }
+ double operator()(double, const accel_args&) const { return 1; }
};
}
diff --git a/common/accel-power.hpp b/common/accel-power.hpp
index c8faabb..8e3f417 100644
--- a/common/accel-power.hpp
+++ b/common/accel-power.hpp
@@ -2,25 +2,162 @@
#include "rawaccel-base.hpp"
-#include <math.h>
+#include <float.h>
namespace rawaccel {
- /// <summary> Struct to hold power (non-additive) acceleration implementation. </summary>
- struct power {
- double pre_scale;
- double exponent;
- double post_scale;
+ struct power_base {
+ vec2d offset;
+ double scale;
+ double constant;
+
+ power_base(const accel_args& args)
+ {
+ auto n = args.exponent_power;
+
+ if (args.cap_mode != cap_mode::io) {
+ scale = args.scale;
+ }
+ else if (args.gain) {
+ scale = scale_from_gain_point(args.cap.x, args.cap.y, n);
+ }
+ else {
+ /*
+ * special case for legacy + io cap mode
+ *
+ * offset is ignored because of the circular dependency:
+ * scale -> constant -> offset
+ */
+ offset = {};
+ constant = 0;
+ scale = scale_from_sens_point(args.cap.x, args.cap.y, n, constant);
+ return;
+ }
+
+ offset.x = gain_inverse(args.output_offset, n, scale);
+ offset.y = args.output_offset;
+ constant = offset.x * offset.y * n / (n + 1);
+ }
+
+ double base_fn(double x, const accel_args& args) const
+ {
+ if (x <= offset.x) {
+ return offset.y;
+ }
+ else {
+ return pow(scale * x, args.exponent_power) + constant / x;
+ }
+ }
+
+ static double gain(double input, double power, double scale)
+ {
+ return (power + 1) * pow(input * scale, power);
+ }
+
+ static double gain_inverse(double gain, double power, double scale)
+ {
+ return pow(gain / (power + 1), 1 / power) / scale;
+ }
+
+ static double scale_from_gain_point(double input, double gain, double power)
+ {
+ return pow(gain / (power + 1), 1 / power) / input;
+ }
+
+ static double scale_from_sens_point(double input, double sens, double power, double C)
+ {
+ return pow(sens - C / input, 1 / power) / input;
+ }
+ };
+
+ template <bool Gain> struct power;
+
+ template <>
+ struct power<LEGACY> : power_base {
+ double cap = DBL_MAX;
+
+ power(const accel_args& args) :
+ power_base(args)
+ {
+
+ switch (args.cap_mode){
+ case cap_mode::io:
+ cap = args.cap.y;
+ break;
+ case cap_mode::in:
+ if (args.cap.x > 0) cap = base_fn(args.cap.x, args);
+ break;
+ case cap_mode::out:
+ default:
+ if (args.cap.y > 0) cap = args.cap.y;
+ break;
+ }
+ }
+
+ double operator()(double speed, const accel_args& args) const
+ {
+ return minsd(base_fn(speed, args), cap);
+ }
+
+ };
+
+ template <>
+ struct power<GAIN> : power_base {
+ vec2d cap = { DBL_MAX, DBL_MAX };
+ double constant_b;
power(const accel_args& args) :
- pre_scale(args.scale),
- exponent(args.exponent),
- post_scale(args.weight) {}
+ power_base(args)
+ {
+ switch (args.cap_mode) {
+ case cap_mode::io:
+ cap = args.cap;
+ break;
+ case cap_mode::in:
+ if (args.cap.x > 0) {
+
+ if (args.cap.x <= offset.x) {
+ cap.x = 0;
+ cap.y = offset.y;
+ constant_b = 0;
+ return;
+ }
+
+ cap.x = args.cap.x;
+ cap.y = gain(
+ args.cap.x,
+ args.exponent_power,
+ scale);
+ }
+ break;
+ case cap_mode::out:
+ default:
+ if (args.cap.y > 0) {
+ cap.x = gain_inverse(
+ args.cap.y,
+ args.exponent_power,
+ scale);
+ cap.y = args.cap.y;
+ }
+ break;
+ }
+
+ constant_b = integration_constant(cap.x, cap.y, base_fn(cap.x, args));
+ }
+
+ double operator()(double speed, const accel_args& args) const
+ {
+ if (speed < cap.x) {
+ return base_fn(speed, args);
+ }
+ else {
+ return cap.y + constant_b / speed;
+ }
+ }
- double operator()(double speed) const
+ static double integration_constant(double input, double gain, double output)
{
- // f(x) = (mx)^k
- return post_scale * pow(speed * pre_scale, exponent);
+ return (output - gain) * input;
}
};
diff --git a/common/accel-union.hpp b/common/accel-union.hpp
index 8495a62..136db44 100644
--- a/common/accel-union.hpp
+++ b/common/accel-union.hpp
@@ -2,101 +2,56 @@
#include "accel-classic.hpp"
#include "accel-jump.hpp"
-#include "accel-natural.hpp"
-#include "accel-power.hpp"
+#include "accel-lookup.hpp"
#include "accel-motivity.hpp"
+#include "accel-natural.hpp"
#include "accel-noaccel.hpp"
+#include "accel-power.hpp"
namespace rawaccel {
- enum class internal_mode {
- classic_lgcy,
- classic_gain,
- jump_lgcy,
- jump_gain,
- natural_lgcy,
- natural_gain,
- motivity_lgcy,
- motivity_gain,
- power,
- lut_arb,
- lut_log,
- lut_lin,
- noaccel
- };
-
- constexpr internal_mode make_mode(accel_mode mode, spaced_lut_mode lut_mode, bool legacy)
- {
- if (lut_mode != spaced_lut_mode::off) {
- switch (lut_mode) {
- case spaced_lut_mode::binlog: return internal_mode::lut_log;
- case spaced_lut_mode::linear: return internal_mode::lut_lin;
- default: return internal_mode::noaccel;
- }
- }
- else if (mode == accel_mode::power) {
- return internal_mode::power;
- }
- else if (mode == accel_mode::arb_lookup) {
- return internal_mode::lut_arb;
- }
- else if (mode >= accel_mode::noaccel) {
- return internal_mode::noaccel;
- }
- else {
- int im = static_cast<int>(mode) * 2 + (legacy ? 0 : 1);
- return static_cast<internal_mode>(im);
+ union accel_union {
+ accel_noaccel noaccel;
+ lookup lut;
+ classic<GAIN> classic_g;
+ classic<LEGACY> classic_l;
+ jump<GAIN> jump_g;
+ jump<LEGACY> jump_l;
+ natural<GAIN> natural_g;
+ natural<LEGACY> natural_l;
+ power<GAIN> power_g;
+ power<LEGACY> power_l;
+ loglog_sigmoid<GAIN> loglog_sigmoid_g;
+ loglog_sigmoid<LEGACY> loglog_sigmoid_l;
+
+ template <template <bool> class AccelTemplate, typename Visitor>
+ auto visit_helper(Visitor vis, bool gain)
+ {
+ if (gain) return vis(reinterpret_cast<AccelTemplate<GAIN>&>(*this));
+ else return vis(reinterpret_cast<AccelTemplate<LEGACY>&>(*this));
}
- }
-
- constexpr internal_mode make_mode(const accel_args& args)
- {
- return make_mode(args.mode, args.spaced_args.mode, args.legacy);
- }
- template <typename Visitor, typename AccelUnion>
- constexpr auto visit_accel(Visitor vis, internal_mode mode, AccelUnion&& u)
- {
- switch (mode) {
- case internal_mode::classic_lgcy: return vis(u.classic_l);
- case internal_mode::classic_gain: return vis(u.classic_g);
- case internal_mode::jump_lgcy: return vis(u.jump_l);
- case internal_mode::jump_gain: return vis(u.jump_g);
- case internal_mode::natural_lgcy: return vis(u.natural_l);
- case internal_mode::natural_gain: return vis(u.natural_g);
- case internal_mode::motivity_lgcy: return vis(u.motivity_l);
- case internal_mode::motivity_gain: return vis(u.motivity_g);
- case internal_mode::power: return vis(u.power);
- case internal_mode::lut_arb: return vis(u.arb_lut);
- case internal_mode::lut_log: return vis(u.log_lut);
- case internal_mode::lut_lin: return vis(u.lin_lut);
- default: return vis(u.noaccel);
+ template <typename Visitor>
+ auto visit(Visitor vis, const accel_args& args)
+ {
+ switch (args.mode) {
+ case accel_mode::classic: return visit_helper<classic>(vis, args.gain);
+ case accel_mode::jump: return visit_helper<jump>(vis, args.gain);
+ case accel_mode::natural: return visit_helper<natural>(vis, args.gain);
+ case accel_mode::motivity: return visit_helper<loglog_sigmoid>(vis, args.gain);
+ case accel_mode::power: return visit_helper<power>(vis, args.gain);
+ case accel_mode::lookup: return vis(lut);
+ default: return vis(noaccel);
+ }
}
- }
-
- union accel_union {
- classic classic_g;
- classic_legacy classic_l;
- jump jump_g;
- jump_legacy jump_l;
- natural natural_g;
- natural_legacy natural_l;
- power power;
- sigmoid motivity_l;
- motivity motivity_g;
- linear_lut lin_lut;
- binlog_lut log_lut;
- arbitrary_lut arb_lut;
- accel_noaccel noaccel = {};
- accel_union(const accel_args& args)
+ void init(const accel_args& args)
{
- visit_accel([&](auto& impl) {
+ visit([&](auto& impl) {
impl = { args };
- }, make_mode(args), *this);
+ }, args);
}
- accel_union() = default;
};
}
diff --git a/common/common.vcxitems b/common/common.vcxitems
index 296fbfd..b49acd2 100644
--- a/common/common.vcxitems
+++ b/common/common.vcxitems
@@ -15,7 +15,6 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)accel-classic.hpp" />
- <ClInclude Include="$(MSBuildThisFileDirectory)accel-invoke.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)accel-jump.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)accel-lookup.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)accel-motivity.hpp" />
@@ -31,7 +30,7 @@
<ClInclude Include="$(MSBuildThisFileDirectory)rawaccel-version.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)rawaccel.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)utility-install.hpp" />
- <ClInclude Include="$(MSBuildThisFileDirectory)vec2.h" />
+ <ClInclude Include="$(MSBuildThisFileDirectory)math-vec2.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)utility.hpp" />
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/common/math-vec2.hpp b/common/math-vec2.hpp
new file mode 100644
index 0000000..f84c4c0
--- /dev/null
+++ b/common/math-vec2.hpp
@@ -0,0 +1,37 @@
+#pragma once
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+
+template <typename T>
+struct vec2 {
+ T x;
+ T y;
+};
+
+using vec2d = vec2<double>;
+
+inline vec2d direction(double degrees)
+{
+ double radians = degrees * M_PI / 180;
+ return { cos(radians), sin(radians) };
+}
+
+constexpr vec2d rotate(const vec2d& v, const vec2d& direction)
+{
+ return {
+ v.x * direction.x - v.y * direction.y,
+ v.x * direction.y + v.y * direction.x
+ };
+}
+
+inline double magnitude(const vec2d& v)
+{
+ return sqrt(v.x * v.x + v.y * v.y);
+}
+
+
+inline double lp_distance(const vec2d& v, double p)
+{
+ return pow(pow(v.x, p) + pow(v.y, p), 1 / p);
+}
diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp
index c1b2db3..91f58dc 100644
--- a/common/rawaccel-base.hpp
+++ b/common/rawaccel-base.hpp
@@ -1,6 +1,6 @@
#pragma once
-#include "vec2.h"
+#include "math-vec2.hpp"
namespace rawaccel {
using milliseconds = double;
@@ -14,96 +14,78 @@ namespace rawaccel {
inline constexpr milliseconds WRITE_DELAY = 1000;
inline constexpr size_t MAX_DEV_ID_LEN = 200;
+ inline constexpr size_t MAX_NAME_LEN = 256;
- inline constexpr size_t SPACED_LUT_CAPACITY = 1025;
- inline constexpr size_t ARB_LUT_CAPACITY = SPACED_LUT_CAPACITY / 4;
+ inline constexpr size_t LUT_RAW_DATA_CAPACITY = 514;
+ inline constexpr size_t LUT_POINTS_CAPACITY = LUT_RAW_DATA_CAPACITY / 2;
inline constexpr double MAX_NORM = 16;
- inline constexpr double PI = 3.14159265358979323846;
+ inline constexpr bool LEGACY = 0;
+ inline constexpr bool GAIN = 1;
+
enum class accel_mode {
classic,
jump,
natural,
motivity,
power,
- arb_lookup,
+ lookup,
noaccel
};
- enum class spaced_lut_mode {
- off,
- binlog,
- linear
- };
-
- struct spaced_lut_args {
- spaced_lut_mode mode = spaced_lut_mode::off;
- bool transfer = true;
- unsigned char partitions = 2;
- short num_elements = 8;
- double start = 0;
- double stop = 8;
- };
-
- struct table_args {
- bool velocity = true;
- int length = 0;
- vec2<float> data[ARB_LUT_CAPACITY] = {};
+ enum class cap_mode {
+ io, in, out
};
struct accel_args {
accel_mode mode = accel_mode::noaccel;
- bool legacy = false;
+ bool gain = 1;
- double offset = 0;
- double cap = 1.5;
- double accel_classic = 0.005;
+ double input_offset = 0;
+ double output_offset = 0;
+ double acceleration = 0.005;
double decay_rate = 0.1;
double growth_rate = 1;
double motivity = 1.5;
- double power = 2;
+ double exponent_classic = 2;
double scale = 1;
- double weight = 1;
- double exponent = 0.05;
+ double exponent_power = 0.05;
double limit = 1.5;
double midpoint = 5;
double smooth = 0.5;
- spaced_lut_args spaced_args;
- table_args arb_args;
+ vec2d cap = { 15, 1.5 };
+ cap_mode cap_mode = cap_mode::out;
+
+ int length = 0;
+ mutable float data[LUT_RAW_DATA_CAPACITY] = {};
};
- struct domain_args {
- vec2d domain_weights = { 1, 1 };
+
+ struct profile {
+ wchar_t name[MAX_NAME_LEN] = L"default";
+
+ bool whole = true;
double lp_norm = 2;
- };
+ vec2d domain_weights = { 1, 1 };
+ vec2d range_weights = { 1, 1 };
+
+ accel_args accel_x;
+ accel_args accel_y;
+
+ double sensitivity = 1;
+ double yx_sens_ratio = 1;
+ double lr_sens_ratio = 1;
+ double ud_sens_ratio = 1;
- struct settings {
double degrees_rotation = 0;
+
double degrees_snap = 0;
- bool combine_mags = true;
- double dpi = 1000;
+
double speed_min = 0;
double speed_max = 0;
-
- vec2<accel_args> argsv;
- vec2d sens = { 1, 1 };
- vec2d dir_multipliers = { 1, 1 };
- domain_args dom_args = {};
- vec2d range_weights = { 1, 1 };
-
- milliseconds time_min = DEFAULT_TIME_MIN;
- milliseconds time_max = DEFAULT_TIME_MAX;
-
- bool ignore = false;
- wchar_t device_id[MAX_DEV_ID_LEN] = {};
};
- template <typename AccelFunc>
- inline double apply_weighted(AccelFunc&& f, double x, double w)
- {
- return 1 + (f(x) - 1) * w;
- }
}
diff --git a/common/rawaccel-io-def.h b/common/rawaccel-io-def.h
index 399e0f2..2f67b8f 100644
--- a/common/rawaccel-io-def.h
+++ b/common/rawaccel-io-def.h
@@ -8,8 +8,8 @@
#include <Windows.h>
#endif
-#define RA_DEV_TYPE 0x8888u
-
-#define RA_READ CTL_CODE(RA_DEV_TYPE, 0x888, METHOD_BUFFERED, FILE_ANY_ACCESS)
-#define RA_WRITE CTL_CODE(RA_DEV_TYPE, 0x889, METHOD_BUFFERED, FILE_ANY_ACCESS)
-#define RA_GET_VERSION CTL_CODE(RA_DEV_TYPE, 0x88a, METHOD_BUFFERED, FILE_ANY_ACCESS)
+namespace rawaccel {
+ constexpr ULONG READ = (ULONG)CTL_CODE(0x8888u, 0x888, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ constexpr ULONG WRITE = (ULONG)CTL_CODE(0x8888u, 0x889, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ constexpr ULONG GET_VERSION = (ULONG)CTL_CODE(0x8888u, 0x88a, METHOD_BUFFERED, FILE_ANY_ACCESS);
+} \ No newline at end of file
diff --git a/common/rawaccel-io.hpp b/common/rawaccel-io.hpp
index a80e254..046ac3d 100644
--- a/common/rawaccel-io.hpp
+++ b/common/rawaccel-io.hpp
@@ -5,8 +5,7 @@
#include "rawaccel-error.hpp"
#include "rawaccel.hpp"
-#pragma warning(push)
-#pragma warning(disable:4245) // int -> DWORD conversion while passing CTL_CODE
+#include <memory>
namespace rawaccel {
@@ -40,14 +39,54 @@ namespace rawaccel {
}
}
- inline void read(io_t& args)
+ inline std::unique_ptr<std::byte[]> read()
{
- io_control(RA_READ, NULL, 0, &args, sizeof(io_t));
+ io_base base_data;
+
+ io_control(READ, NULL, 0, &base_data, sizeof(io_base));
+
+ size_t size = sizeof(base_data);
+
+ if (base_data.modifier_data_size == 0) {
+ // driver has no data, but it's more useful to return something,
+ // so return a default modifier_settings object along with base data
+
+ size += sizeof(modifier_settings);
+ base_data.modifier_data_size = 1;
+ auto bytes = std::make_unique<std::byte[]>(size);
+ *reinterpret_cast<io_base*>(bytes.get()) = base_data;
+ *reinterpret_cast<modifier_settings*>(bytes.get() + sizeof(io_base)) = {};
+ return bytes;
+ }
+ else {
+ size += sizeof(modifier_settings) * base_data.modifier_data_size;
+ size += sizeof(device_settings) * base_data.device_data_size;
+ auto bytes = std::make_unique<std::byte[]>(size);
+ io_control(READ, NULL, 0, bytes.get(), DWORD(size));
+ return bytes;
+ }
}
- inline void write(const io_t& args)
+ // buffer must point to at least sizeof(io_base) bytes
+ inline void write(const void* buffer)
{
- io_control(RA_WRITE, const_cast<io_t*>(&args), sizeof(io_t), NULL, 0);
+ if (buffer == nullptr) throw io_error("write buffer is null");
+
+ auto* base_ptr = static_cast<const io_base*>(buffer);
+ auto size = sizeof(io_base);
+ size += base_ptr->modifier_data_size * sizeof(modifier_settings);
+ size += base_ptr->device_data_size * sizeof(device_settings);
+
+ if (size > DWORD(-1)) throw io_error("write buffer is too large");
+
+ io_control(WRITE, const_cast<void*>(buffer), DWORD(size), NULL, 0);
+ }
+
+ inline void reset()
+ {
+ io_base base_data{};
+ // all modifier/device data is cleared when a default io_base is passed
+ io_control(WRITE, &base_data, sizeof(io_base), NULL, 0);
}
inline version_t get_version()
@@ -55,7 +94,7 @@ namespace rawaccel {
version_t v;
try {
- io_control(RA_GET_VERSION, NULL, 0, &v, sizeof(version_t));
+ io_control(GET_VERSION, NULL, 0, &v, sizeof(version_t));
}
catch (const sys_error&) {
// assume request is not implemented (< 1.3)
@@ -81,5 +120,3 @@ namespace rawaccel {
}
}
-
-#pragma warning(pop)
diff --git a/common/rawaccel-validate.hpp b/common/rawaccel-validate.hpp
index a03f56a..b84fdb7 100644
--- a/common/rawaccel-validate.hpp
+++ b/common/rawaccel-validate.hpp
@@ -5,7 +5,7 @@
namespace rawaccel {
- struct valid_ret_t {
+ struct valid_profile_ret_t {
int last_x = 0;
int last_y = 0;
int count = 0;
@@ -16,10 +16,19 @@ namespace rawaccel {
}
};
+ struct valid_device_ret_t {
+ int count = 0;
+
+ explicit operator bool() const
+ {
+ return count == 0;
+ }
+ };
+
template <typename MsgHandler = noop>
- valid_ret_t valid(const settings& args, MsgHandler fn = {})
+ valid_profile_ret_t valid(const profile& args, MsgHandler fn = {})
{
- valid_ret_t ret;
+ valid_profile_ret_t ret;
auto error = [&](auto msg) {
++ret.count;
@@ -27,95 +36,83 @@ namespace rawaccel {
};
auto check_accel = [&error](const accel_args& args) {
- static_assert(SPACED_LUT_CAPACITY == 1025, "update error msg");
+ static_assert(LUT_POINTS_CAPACITY == 257, "update error msg");
- const auto& lut_args = args.spaced_args;
-
- if (lut_args.partitions <= 0) {
- error("lut partitions"" must be positive");
- }
-
- if (lut_args.mode == spaced_lut_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 (args.mode == accel_mode::lookup) {
+ if (args.length < 4) {
+ error("lookup mode requires at least 2 points");
}
-
- if (lut_args.num_elements < 2 ||
- lut_args.num_elements > 1025) {
- error("num must be between 2 and 1025");
+ else if (args.length > ra::LUT_RAW_DATA_CAPACITY) {
+ error("too many data points (max=257)");
}
}
- else if (lut_args.mode == spaced_lut_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");
- }
+ else if (args.length > ra::LUT_RAW_DATA_CAPACITY) {
+ error("data size > max");
}
- if (args.mode == accel_mode::arb_lookup) {
- if (args.arb_args.length < 2) {
- error("lookup mode requires at least 2 points");
- }
+ if (args.input_offset < 0) {
+ error("offset can not be negative");
}
- if (args.offset < 0) {
+ if (args.output_offset < 0) {
error("offset can not be negative");
}
- else if (args.mode == accel_mode::jump && args.offset == 0) {
- error("offset can not be 0");
- }
- if (args.cap < 0) {
- error("cap"" must not be negative");
+ bool jump_or_io_cap =
+ (args.mode == accel_mode::jump ||
+ ((args.mode == accel_mode::classic || args.mode == accel_mode::power) &&
+ args.cap_mode == cap_mode::io));
+
+ if (args.cap.x < 0) {
+ error("cap (input) can not be negative");
}
- else if (args.mode == accel_mode::jump && args.cap == 0) {
- error("cap can not be 0");
+ else if (args.cap.x == 0 && jump_or_io_cap) {
+ error("cap (input) can not be 0");
}
- if (args.growth_rate <= 0 ||
- args.decay_rate <= 0 ||
- args.accel_classic <= 0) {
- error("acceleration"" must be positive");
+ if (args.cap.y < 0) {
+ error("cap (output) can not be negative");
+ }
+ else if (args.cap.y == 0 && jump_or_io_cap) {
+ error("cap (output) can not be 0");
}
- if (args.motivity <= 1) {
- error("motivity must be greater than 1");
+ if ((args.mode == accel_mode::classic &&
+ args.cap.x > 0 &&
+ args.cap.x < args.input_offset &&
+ args.cap_mode != cap_mode::out) ||
+ (args.mode == accel_mode::power &&
+ args.cap.y > 0 &&
+ args.cap.y < args.output_offset &&
+ args.cap_mode != cap_mode::in)) {
+ error("cap < offset");
}
- if (args.power <= 1) {
- error("power must be greater than 1");
+ if (args.acceleration <= 0) {
+ error("acceleration"" must be positive");
}
if (args.scale <= 0) {
error("scale"" must be positive");
}
- if (args.weight <= 0) {
- error("weight"" must be positive");
+ if (args.growth_rate <= 0) {
+ error("growth rate"" must be positive");
+ }
+
+ if (args.decay_rate <= 0) {
+ error("decay rate"" must be positive");
}
- if (args.exponent <= 0) {
+ if (args.motivity <= 1) {
+ error("motivity must be greater than 1");
+ }
+
+ if (args.exponent_classic <= 1) {
+ error("exponent must be greater than 1");
+ }
+
+ if (args.exponent_power <= 0) {
error("exponent"" must be positive");
}
@@ -133,16 +130,16 @@ namespace rawaccel {
};
- check_accel(args.argsv.x);
+ check_accel(args.accel_x);
- if (!args.combine_mags) {
+ if (!args.whole) {
ret.last_x = ret.count;
- check_accel(args.argsv.y);
+ check_accel(args.accel_y);
ret.last_y = ret.count;
}
- if (args.dpi <= 0) {
- error("dpi"" must be positive");
+ if (args.name[0] == L'\0') {
+ error("profile name can not be empty");
}
if (args.speed_max < 0) {
@@ -156,36 +153,61 @@ namespace rawaccel {
error("snap angle must be between 0 and 45 degrees");
}
- if (args.sens.x == 0 || args.sens.y == 0) {
+ if (args.sensitivity == 0) {
error("sens multiplier is 0");
}
+
+ if (args.yx_sens_ratio == 0) {
+ error("Y/X sens ratio is 0");
+ }
- if (args.dom_args.domain_weights.x <= 0 ||
- args.dom_args.domain_weights.y <= 0) {
+ if (args.domain_weights.x <= 0 ||
+ args.domain_weights.y <= 0) {
error("domain weights"" must be positive");
}
- if (args.dir_multipliers.x <= 0 || args.dir_multipliers.y <= 0) {
- error("directional multipliers must be positive");
+ if (args.lr_sens_ratio <= 0 || args.ud_sens_ratio <= 0) {
+ error("sens ratio must be positive");
}
- if (args.dom_args.lp_norm < 2) {
- error("Lp norm is less than 2 (default=2)");
+ if (args.lp_norm <= 0) {
+ error("Lp norm must be positive (default=2)");
}
if (args.range_weights.x <= 0 || args.range_weights.y <= 0) {
error("range weights"" must be positive");
}
- if (args.time_min <= 0) {
+ return ret;
+ }
+
+ template <typename MsgHandler = noop>
+ valid_device_ret_t valid(const device_settings& args, MsgHandler fn = {})
+ {
+ valid_device_ret_t ret;
+
+ auto error = [&](auto msg) {
+ ++ret.count;
+ fn(msg);
+ };
+
+
+ if (args.config.dpi < 0) {
+ error("dpi"" can not be negative");
+ }
+
+ if (args.config.polling_rate < 0) {
+ error("polling rate"" can not be negative");
+ }
+
+ if (args.config.clamp.min <= 0) {
error("minimum time"" must be positive");
}
- if (args.time_max < args.time_min) {
+ if (args.config.clamp.max < args.config.clamp.min) {
error("max time is less than min time");
}
return ret;
}
-
}
diff --git a/common/rawaccel-version.h b/common/rawaccel-version.h
index 384ba6f..f3f684c 100644
--- a/common/rawaccel-version.h
+++ b/common/rawaccel-version.h
@@ -1,10 +1,10 @@
#pragma once
#define RA_VER_MAJOR 1
-#define RA_VER_MINOR 5
+#define RA_VER_MINOR 6
#define RA_VER_PATCH 0
-#define RA_OS "Win7+"
+#define RA_OS "Win10+"
#define RA_M_STR_HELPER(x) #x
#define RA_M_STR(x) RA_M_STR_HELPER(x)
@@ -30,7 +30,7 @@ namespace rawaccel {
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, 5, 0 };
+ inline constexpr version_t min_driver_version = { 1, 6, 0 };
#endif
}
diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp
index 4e8b46c..b12fb8b 100644
--- a/common/rawaccel.hpp
+++ b/common/rawaccel.hpp
@@ -1,83 +1,136 @@
#pragma once
-#include "accel-invoke.hpp"
+#include "accel-union.hpp"
namespace rawaccel {
- inline vec2d direction(double degrees)
- {
- double radians = degrees * PI / 180;
- return { cos(radians), sin(radians) };
- }
+ struct time_clamp {
+ milliseconds min = DEFAULT_TIME_MIN;
+ milliseconds max = DEFAULT_TIME_MAX;
+ };
+
+ struct device_config {
+ bool disable = false;
+ bool set_extra_info = false;
+ int dpi = 0;
+ int polling_rate = 0;
+ time_clamp clamp;
+ };
+
+ struct device_settings {
+ wchar_t name[MAX_NAME_LEN] = {};
+ wchar_t profile[MAX_NAME_LEN] = {};
+ wchar_t id[MAX_DEV_ID_LEN] = {};
+ device_config config;
+ };
+
+ enum class distance_mode : unsigned char {
+ separate,
+ max,
+ Lp,
+ euclidean,
+ };
+
+ struct modifier_flags {
+ bool apply_rotate = 0;
+ bool compute_ref_angle = 0;
+ bool apply_snap = 0;
+ bool clamp_speed = 0;
+ distance_mode dist_mode = {};
+ bool apply_directional_weight = 0;
+ bool apply_dir_mul_x = 0;
+ bool apply_dir_mul_y = 0;
+
+ modifier_flags(const profile& args)
+ {
+ clamp_speed = args.speed_max > 0 && args.speed_min <= args.speed_max;
+ apply_rotate = args.degrees_rotation != 0;
+ apply_snap = args.degrees_snap != 0;
+ apply_directional_weight = args.range_weights.x != args.range_weights.y;
+ compute_ref_angle = apply_snap || apply_directional_weight;
+ apply_dir_mul_x = args.lr_sens_ratio != 1;
+ apply_dir_mul_y = args.ud_sens_ratio != 1;
+
+ if (!args.whole) {
+ dist_mode = distance_mode::separate;
+ }
+ else if (args.lp_norm >= MAX_NORM || args.lp_norm <= 0) {
+ dist_mode = distance_mode::max;
+ }
+ else if (args.lp_norm != 2) {
+ dist_mode = distance_mode::Lp;
+ }
+ else {
+ dist_mode = distance_mode::euclidean;
+ }
+ }
+
+ modifier_flags() = default;
+ };
+
+ struct modifier_settings {
+ profile prof;
+
+ struct data_t {
+ modifier_flags flags;
+ vec2d rot_direction;
+ accel_union accel_x;
+ accel_union accel_y;
+ } data = {};
+ };
- constexpr vec2d rotate(const vec2d& v, const vec2d& direction)
+ inline void init_data(modifier_settings& settings)
{
- return {
- v.x * direction.x - v.y * direction.y,
- v.x * direction.y + v.y * direction.x
+ auto set_accel = [](accel_union& u, const accel_args& args) {
+ u.visit([&](auto& impl) {
+ impl = { args };
+ }, args);
};
- }
- inline double magnitude(const vec2d& v)
- {
- return sqrt(v.x * v.x + v.y * v.y);
- }
+ set_accel(settings.data.accel_x, settings.prof.accel_x);
+ set_accel(settings.data.accel_y, settings.prof.accel_y);
- inline double lp_distance(const vec2d& v, double p)
- {
- return pow(pow(v.x, p) + pow(v.y, p), 1 / p);
+ settings.data.rot_direction = direction(settings.prof.degrees_rotation);
+
+ settings.data.flags = modifier_flags(settings.prof);
}
- class mouse_modifier {
- public:
- enum accel_distance_mode : unsigned char {
- separate,
- max,
- Lp,
- euclidean,
- };
+ struct io_base {
+ device_config default_dev_cfg;
+ unsigned modifier_data_size = 0;
+ unsigned device_data_size = 0;
+ };
- bool apply_rotate = false;
- bool compute_ref_angle = false;
- bool apply_snap = false;
- bool cap_speed = false;
- accel_distance_mode dist_mode = euclidean;
- bool apply_directional_weight = false;
- bool apply_dir_mul_x = false;
- bool apply_dir_mul_y = false;
-
- vec2d rot_vec = { 1, 0 };
- double snap = 0;
- double dpi_norm_factor = 1;
- double speed_min = 0;
- double speed_max = 0;
- vec2d domain_weights = { 1, 1 };
- double p = 2;
- vec2d range_weights = { 1, 1 };
- vec2d directional_multipliers = { 1, 1 };
- vec2d sensitivity = { 1, 1 };
- vec2<accel_union> accel;
+ static_assert(alignof(io_base) == alignof(modifier_settings) && alignof(modifier_settings) == alignof(device_settings));
+ class modifier {
+ public:
#ifdef _KERNEL_MODE
__forceinline
#endif
- void modify(vec2d& in, const vec2<accel_invoker>& inv, milliseconds time = 1) const
+ void modify(vec2d& in, const modifier_settings& settings, double dpi_factor, milliseconds time) const
{
- double ips_factor = dpi_norm_factor / time;
+ auto& args = settings.prof;
+ auto& data = settings.data;
+ auto& flags = settings.data.flags;
+
double reference_angle = 0;
+ double ips_factor = dpi_factor / time;
- if (apply_rotate) in = rotate(in, rot_vec);
+ if (flags.apply_rotate) in = rotate(in, data.rot_direction);
- if (compute_ref_angle && in.y != 0) {
+ if (flags.compute_ref_angle && in.y != 0) {
if (in.x == 0) {
- reference_angle = PI / 2;
+ reference_angle = M_PI / 2;
}
else {
reference_angle = atan(fabs(in.y / in.x));
- if (apply_snap) {
- if (reference_angle > PI / 2 - snap) {
- reference_angle = PI / 2;
+ if (flags.apply_snap) {
+ double snap = args.degrees_snap * M_PI / 180;
+
+ if (reference_angle > M_PI / 2 - snap) {
+ reference_angle = M_PI / 2;
in = { 0, _copysign(magnitude(in), in.y) };
}
else if (reference_angle < snap) {
@@ -88,92 +141,90 @@ namespace rawaccel {
}
}
- if (cap_speed) {
+ if (flags.clamp_speed) {
double speed = magnitude(in) * ips_factor;
- double ratio = clampsd(speed, speed_min, speed_max) / speed;
+ double ratio = clampsd(speed, args.speed_min, args.speed_max) / speed;
in.x *= ratio;
in.y *= ratio;
}
vec2d abs_weighted_vel = {
- fabs(in.x * ips_factor * domain_weights.x),
- fabs(in.y * ips_factor * domain_weights.y)
+ fabs(in.x * ips_factor * args.domain_weights.x),
+ fabs(in.y * ips_factor * args.domain_weights.y)
};
- if (dist_mode == separate) {
- in.x *= inv.x.invoke(accel.x, abs_weighted_vel.x, range_weights.x);
- in.y *= inv.y.invoke(accel.y, abs_weighted_vel.y, range_weights.y);
+ if (flags.dist_mode == distance_mode::separate) {
+ in.x *= (*cb_x)(data.accel_x, args.accel_x, abs_weighted_vel.x, args.range_weights.x);
+ in.y *= (*cb_y)(data.accel_y, args.accel_y, abs_weighted_vel.y, args.range_weights.y);
}
- else {
+ else {
double speed;
- if (dist_mode == max) {
+ if (flags.dist_mode == distance_mode::max) {
speed = maxsd(abs_weighted_vel.x, abs_weighted_vel.y);
}
- else if (dist_mode == Lp) {
- speed = lp_distance(abs_weighted_vel, p);
+ else if (flags.dist_mode == distance_mode::Lp) {
+ speed = lp_distance(abs_weighted_vel, args.lp_norm);
}
else {
speed = magnitude(abs_weighted_vel);
}
- double weight = range_weights.x;
+ double weight = args.range_weights.x;
- if (apply_directional_weight) {
- double diff = range_weights.y - range_weights.x;
- weight += 2 / PI * reference_angle * diff;
+ if (flags.apply_directional_weight) {
+ double diff = args.range_weights.y - args.range_weights.x;
+ weight += 2 / M_PI * reference_angle * diff;
}
- double scale = inv.x.invoke(accel.x, speed, weight);
+ double scale = (*cb_x)(data.accel_x, args.accel_x, speed, weight);
in.x *= scale;
in.y *= scale;
}
- if (apply_dir_mul_x && in.x < 0) {
- in.x *= directional_multipliers.x;
- }
+ double dpi_adjusted_sens = args.sensitivity * dpi_factor;
+ in.x *= dpi_adjusted_sens;
+ in.y *= dpi_adjusted_sens * args.yx_sens_ratio;
- if (apply_dir_mul_y && in.y < 0) {
- in.y *= directional_multipliers.y;
+ if (flags.apply_dir_mul_x && in.x < 0) {
+ in.x *= args.lr_sens_ratio;
}
- in.x *= sensitivity.x;
- in.y *= sensitivity.y;
+ if (flags.apply_dir_mul_y && in.y < 0) {
+ in.y *= args.ud_sens_ratio;
+ }
}
- mouse_modifier(const settings& args) :
- rot_vec(direction(args.degrees_rotation)),
- snap(args.degrees_snap * PI / 180),
- dpi_norm_factor(1000 / args.dpi),
- speed_min(args.speed_min),
- speed_max(args.speed_max),
- p(args.dom_args.lp_norm),
- domain_weights(args.dom_args.domain_weights),
- range_weights(args.range_weights),
- directional_multipliers(args.dir_multipliers),
- sensitivity(args.sens),
- accel({ { args.argsv.x }, { args.argsv.y } })
+ modifier(modifier_settings& settings)
{
- cap_speed = speed_max > 0 && speed_min <= speed_max;
- apply_rotate = rot_vec.x != 1;
- apply_snap = snap != 0;
- apply_directional_weight = range_weights.x != range_weights.y;
- compute_ref_angle = apply_snap || apply_directional_weight;
- apply_dir_mul_x = directional_multipliers.x != 1;
- apply_dir_mul_y = directional_multipliers.y != 1;
+ set_callback(cb_x, settings.data.accel_x, settings.prof.accel_x);
+ set_callback(cb_y, settings.data.accel_y, settings.prof.accel_y);
+ }
+
+ modifier() = default;
- if (!args.combine_mags) dist_mode = separate;
- else if (p >= MAX_NORM || p <= 0) dist_mode = max;
- else if (p != 2) dist_mode = Lp;
- else dist_mode = euclidean;
+ private:
+ using callback_t = double (*)(const accel_union&, const accel_args&, double, double);
+
+ void set_callback(callback_t& cb, accel_union& u, const accel_args& args)
+ {
+ u.visit([&](auto& impl) {
+ cb = &callback_template<remove_ref_t<decltype(impl)>>;
+ }, args);
}
- mouse_modifier() = default;
- };
+ template <typename AccelFunc>
+ static double callback_template(const accel_union& u,
+ const accel_args& args,
+ double x,
+ double range_weight)
+ {
+ auto& accel_fn = reinterpret_cast<const AccelFunc&>(u);
+ return 1 + (accel_fn(x, args) - 1) * range_weight;
+ }
- struct io_t {
- settings args;
- mouse_modifier mod;
+ callback_t cb_x = &callback_template<accel_noaccel>;
+ callback_t cb_y = &callback_template<accel_noaccel>;
};
} // rawaccel
diff --git a/common/utility-install.hpp b/common/utility-install.hpp
index e1823e4..55ae9d6 100644
--- a/common/utility-install.hpp
+++ b/common/utility-install.hpp
@@ -10,25 +10,24 @@ namespace wr = winreg;
inline const std::wstring DRIVER_NAME = L"rawaccel";
inline const std::wstring DRIVER_FILE_NAME = DRIVER_NAME + L".sys";
+inline const std::wstring DRIVER_ENV_PATH = L"%systemroot%\\system32\\drivers\\" + DRIVER_FILE_NAME;
-fs::path get_sys_path() {
- std::wstring path;
- path.resize(MAX_PATH);
+inline const auto sys_error = [](auto what, DWORD code = GetLastError()) {
+ return std::system_error(code, std::system_category(), what);
+};
- UINT chars_copied = GetSystemDirectoryW(path.data(), MAX_PATH);
- if (chars_copied == 0) throw std::runtime_error("GetSystemDirectory failed");
+inline std::wstring expand(const std::wstring& env_path) {
+ std::wstring path(MAX_PATH, L'\0');
- path.resize(chars_copied);
+ auto len = ExpandEnvironmentStringsW(env_path.c_str(), &path[0], MAX_PATH);
+ if (len == 0) throw sys_error("ExpandEnvironmentStrings failed");
+ path.resize(len - 1);
return path;
}
-fs::path get_target_path() {
- return get_sys_path() / L"drivers" / DRIVER_FILE_NAME;
-}
-
-fs::path make_temp_path(const fs::path& p) {
+inline fs::path make_temp_path(const fs::path& p) {
auto tmp_path = p;
- tmp_path.concat(".tmp");
+ tmp_path.concat(L".tmp");
return tmp_path;
}
diff --git a/common/utility.hpp b/common/utility.hpp
index cbd19e3..2587d91 100644
--- a/common/utility.hpp
+++ b/common/utility.hpp
@@ -35,15 +35,6 @@ namespace rawaccel {
return (v < lo) ? lo : (hi < v) ? hi : v;
}
- constexpr double lerp(double a, double b, double t)
- {
- double x = a + t * (b - a);
- if ((t > 1) == (a < b)) {
- return maxsd(x, b);
- }
- return minsd(x, b);
- }
-
// returns the unbiased exponent of x if x is normal
inline int ilogb(double x)
{
@@ -85,4 +76,10 @@ namespace rawaccel {
template <typename T, typename U>
inline constexpr bool is_same_v = is_same<T, U>::value;
+ template <class T> struct is_rvalue_ref { static constexpr bool value = false; };
+ template <class T> struct is_rvalue_ref<T&&> { static constexpr bool value = true; };
+
+ template <class T>
+ inline constexpr bool is_rvalue_ref_v = is_rvalue_ref<T>::value;
+
}
diff --git a/common/vec2.h b/common/vec2.h
deleted file mode 100644
index 6484e69..0000000
--- a/common/vec2.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-template <typename T>
-struct vec2 {
- T x;
- T y;
-};
-
-using vec2d = vec2<double>;