diff options
| author | JacobPalecki <[email protected]> | 2020-08-31 23:03:46 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2020-08-31 23:03:46 -0700 |
| commit | 471fe599bab6ba0632ddd1dacd20c7fc42db0eee (patch) | |
| tree | 90a82ee14dbb112621657efbd2523ed35f59d154 /common | |
| parent | Merge pull request #16 from JacobPalecki/Misc (diff) | |
| parent | add independent xy accel to driver (diff) | |
| download | rawaccel-471fe599bab6ba0632ddd1dacd20c7fc42db0eee.tar.xz rawaccel-471fe599bab6ba0632ddd1dacd20c7fc42db0eee.zip | |
Merge pull request #17 from a1xd/indep
Indep
Diffstat (limited to 'common')
| -rw-r--r-- | common/accel-base.hpp | 73 | ||||
| -rw-r--r-- | common/accel-classic.hpp | 25 | ||||
| -rw-r--r-- | common/accel-linear.hpp | 11 | ||||
| -rw-r--r-- | common/accel-logarithmic.hpp | 10 | ||||
| -rw-r--r-- | common/accel-natural.hpp | 26 | ||||
| -rw-r--r-- | common/accel-naturalgain.hpp | 23 | ||||
| -rw-r--r-- | common/accel-noaccel.hpp | 7 | ||||
| -rw-r--r-- | common/accel-power.hpp | 33 | ||||
| -rw-r--r-- | common/accel-sigmoid.hpp | 26 | ||||
| -rw-r--r-- | common/accel-sigmoidgain.hpp | 32 | ||||
| -rw-r--r-- | common/common.vcxitems | 2 | ||||
| -rw-r--r-- | common/rawaccel-io.hpp | 27 | ||||
| -rw-r--r-- | common/rawaccel-settings.h | 21 | ||||
| -rw-r--r-- | common/rawaccel.hpp | 266 | ||||
| -rw-r--r-- | common/tagged-union-single.h | 202 |
15 files changed, 260 insertions, 524 deletions
diff --git a/common/accel-base.hpp b/common/accel-base.hpp index f280e3e..560c0b5 100644 --- a/common/accel-base.hpp +++ b/common/accel-base.hpp @@ -1,19 +1,5 @@ #pragma once -#include "vec2.h" - -void bad_arg(const char*); - -#ifndef _KERNEL_MODE - -#include "rawaccel-error.hpp" - -inline void bad_arg(const char* s) { - throw rawaccel::invalid_argument(s); -} - -#endif - namespace rawaccel { /// <summary> Struct to hold arguments for an acceleration function. </summary> @@ -24,55 +10,48 @@ namespace rawaccel { double exponent = 2; double midpoint = 0; double power_scale = 1; + double power_exp = 0.05; + double weight = 1; + double rate = 0; + double scale_cap = 0; double gain_cap = 0; - vec2d weight = { 1, 1 }; }; - /// <summary> - /// Struct to hold common acceleration curve implementation details. - /// </summary> - struct accel_base { + template <typename Func> + struct accel_val_base { + double offset = 0; + double weight = 1; + Func fn; - /// <summary> Coefficients applied to acceleration per axis.</summary> - vec2d weight = { 1, 1 }; + accel_val_base(const accel_args& args) : fn(args) {} - /// <summary> Generally, the acceleration ramp rate.</summary> - double speed_coeff = 0; + }; - accel_base(const accel_args& args) { - verify(args); + template <typename Func> + struct additive_accel : accel_val_base<Func> { - speed_coeff = args.accel; + additive_accel(const accel_args& args) : accel_val_base(args) { + offset = args.offset; weight = args.weight; } - /// <summary> - /// Default transformation of speed -> acceleration. - /// </summary> - inline double accelerate(double speed) const { - return speed_coeff * speed; + inline double operator()(double speed) const { + return 1 + fn(maxsd(speed - offset, 0)) * weight; } - /// <summary> - /// Default transformation of acceleration -> mouse input multipliers. - /// </summary> - inline vec2d scale(double accel_val) const { - return { - weight.x * accel_val + 1, - weight.y * accel_val + 1 - }; + }; + + template <typename Func> + struct nonadditive_accel : accel_val_base<Func> { + + nonadditive_accel(const accel_args& args) : accel_val_base(args) { + if (args.weight != 0) weight = args.weight; } - /// <summary> - /// Verifies arguments as valid. Errors if not. - /// </summary> - /// <param name="args">Arguments to verified.</param> - void verify(const accel_args& args) const { - if (args.accel < 0) bad_arg("accel can not be negative, use a negative weight to compensate"); - if (args.gain_cap > 0 && weight.x != weight.y) bad_arg("weight x and y values must be equal with a gain cap"); + inline double operator()(double speed) const { + return fn(speed) * weight; } - accel_base() = default; }; } diff --git a/common/accel-classic.hpp b/common/accel-classic.hpp index 0a380dd..4cc52ca 100644 --- a/common/accel-classic.hpp +++ b/common/accel-classic.hpp @@ -7,23 +7,20 @@ namespace rawaccel { /// <summary> Struct to hold "classic" (linear raised to power) acceleration implementation. </summary> - struct accel_classic : accel_base { - double exponent; + struct classic_impl { + double accel; + double power; - accel_classic(const accel_args& args) : accel_base(args) { - verify(args); + classic_impl(const accel_args& args) : + accel(args.accel), power(args.exponent - 1) + {} - exponent = args.exponent - 1; - } - - inline double accelerate(double speed) const { - //f(x) = (mx)^k - return pow(speed_coeff * speed, exponent); - } - - void verify(const accel_args& args) const { - if (args.exponent <= 1) bad_arg("exponent must be greater than 1"); + inline double operator()(double speed) const { + //f(x) = (mx)^(k-1) + return pow(accel * speed, power); } }; + + using accel_classic = additive_accel<classic_impl>; } diff --git a/common/accel-linear.hpp b/common/accel-linear.hpp index 5cbb7c6..a943594 100644 --- a/common/accel-linear.hpp +++ b/common/accel-linear.hpp @@ -5,10 +5,17 @@ namespace rawaccel { /// <summary> Struct to hold linear acceleration implementation. </summary> - struct accel_linear : accel_base { + struct linear_impl { + double accel; + + linear_impl(const accel_args& args) : accel(args.accel) {} - using accel_base::accel_base; + inline double operator()(double speed) const { + return accel * speed; + } }; + using accel_linear = additive_accel<linear_impl>; + } diff --git a/common/accel-logarithmic.hpp b/common/accel-logarithmic.hpp index 928eda9..c7991c7 100644 --- a/common/accel-logarithmic.hpp +++ b/common/accel-logarithmic.hpp @@ -7,14 +7,16 @@ namespace rawaccel { /// <summary> Struct to hold logarithmic acceleration implementation. </summary> - struct accel_logarithmic : accel_base { + struct logarithmic_impl { + double accel; - using accel_base::accel_base; + logarithmic_impl(const accel_args& args) : accel(args.accel) {} - inline double accelerate(double speed) const { + inline double operator()(double speed) const { //f(x) = log(m*x+1) - return log(speed_coeff * speed + 1); + return log(accel * speed + 1); } }; + using accel_logarithmic = additive_accel<logarithmic_impl>; } diff --git a/common/accel-natural.hpp b/common/accel-natural.hpp index 8f002e4..c7d0dcd 100644 --- a/common/accel-natural.hpp +++ b/common/accel-natural.hpp @@ -7,25 +7,23 @@ namespace rawaccel { /// <summary> Struct to hold "natural" (vanishing difference) acceleration implementation. </summary> - struct accel_natural : accel_base { - double limit = 1; - double midpoint = 0; - - accel_natural(const accel_args& args) : accel_base(args) { - verify(args); - - limit = args.limit - 1; - speed_coeff /= limit; + struct natural_impl { + double rate; + double limit; + + natural_impl(const accel_args& args) : + rate(args.accel), limit(args.limit - 1) + { + rate /= limit; } - inline double accelerate(double speed) const { + inline double operator()(double speed) const { // f(x) = k(1-e^(-mx)) - return limit - (limit * exp(-speed_coeff * speed)); + return limit - (limit * exp(-rate * speed)); } - void verify(const accel_args& args) const { - if (args.limit <= 1) bad_arg("limit must be greater than 1"); - } }; + using accel_natural = additive_accel<natural_impl>; + } diff --git a/common/accel-naturalgain.hpp b/common/accel-naturalgain.hpp index 95c0be2..646b2bb 100644 --- a/common/accel-naturalgain.hpp +++ b/common/accel-naturalgain.hpp @@ -2,31 +2,22 @@ #include <math.h> -#include "accel-base.hpp" +#include "accel-natural.hpp" namespace rawaccel { /// <summary> Struct to hold "natural" (vanishing difference) gain implementation. </summary> - struct accel_naturalgain : accel_base { - double limit = 1; - double midpoint = 0; + struct naturalgain_impl : natural_impl { - accel_naturalgain(const accel_args& args) : accel_base(args) { - verify(args); + using natural_impl::natural_impl; - limit = args.limit - 1; - speed_coeff /= limit; - } - - inline double accelerate(double speed) const { + inline double operator()(double speed) const { // f(x) = k((e^(-mx)-1)/mx + 1) - double scaled_speed = speed_coeff * speed; + double scaled_speed = rate * speed; return limit * (((exp(-scaled_speed) - 1) / scaled_speed) + 1); } - - void verify(const accel_args& args) const { - if (args.limit <= 1) bad_arg("limit must be greater than 1"); - } + }; + using accel_naturalgain = additive_accel<naturalgain_impl>; } diff --git a/common/accel-noaccel.hpp b/common/accel-noaccel.hpp index b7f730b..ae6f5f8 100644 --- a/common/accel-noaccel.hpp +++ b/common/accel-noaccel.hpp @@ -5,10 +5,13 @@ namespace rawaccel { /// <summary> Struct to hold acceleration implementation which applies no acceleration. </summary> - struct accel_noaccel : accel_base { + struct accel_noaccel { - accel_noaccel(const accel_args&) : accel_base() {} + accel_noaccel(const accel_args&) {} + accel_noaccel() = default; + inline double operator()(double) const { return 1; } + }; } diff --git a/common/accel-power.hpp b/common/accel-power.hpp index 0d5e265..1abfdd1 100644 --- a/common/accel-power.hpp +++ b/common/accel-power.hpp @@ -7,35 +7,20 @@ namespace rawaccel { /// <summary> Struct to hold power (non-additive) acceleration implementation. </summary> - struct accel_power : accel_base { + struct power_impl { + double scale; double exponent; - double offset; - accel_power(const accel_args& args) { - verify(args); + power_impl(const accel_args& args) : + scale(args.power_scale), exponent(args.power_exp) + {} - weight = args.weight; - speed_coeff = args.power_scale; - exponent = args.exponent; - offset = args.offset; - } - - inline double accelerate(double speed) const { + inline double operator()(double speed) const { // f(x) = (mx)^k - return (offset > 0 && speed < 1) ? 1 : pow(speed * speed_coeff, exponent); - } - - inline vec2d scale(double accel_val) const { - return { - weight.x * accel_val, - weight.y * accel_val - }; - } - - void verify(const accel_args& args) const { - if (args.power_scale <= 0) bad_arg("scale must be positive"); - if (args.exponent <= 0) bad_arg("exponent must be greater than 0"); + return pow(speed * scale, exponent); } }; + using accel_power = nonadditive_accel<power_impl>; + } diff --git a/common/accel-sigmoid.hpp b/common/accel-sigmoid.hpp index dc2066d..c8112ee 100644 --- a/common/accel-sigmoid.hpp +++ b/common/accel-sigmoid.hpp @@ -7,26 +7,22 @@ namespace rawaccel { /// <summary> Struct to hold sigmoid (s-shaped) acceleration implementation. </summary> - struct accel_sigmoid : accel_base { - double limit = 1; - double midpoint = 0; + struct sigmoid_impl { + double rate; + double limit; + double midpoint; - accel_sigmoid(const accel_args& args) : accel_base(args) { - verify(args); + sigmoid_impl(const accel_args& args) : + rate(args.accel), limit(args.limit - 1), midpoint(args.midpoint) + {} - limit = args.limit - 1; - midpoint = args.midpoint; - } - - inline double accelerate(double speed) const { + inline double operator()(double speed) const { //f(x) = k/(1+e^(-m(x-c))) - return limit / (exp(-speed_coeff * (speed - midpoint)) + 1); + return limit / (exp(-rate * (speed - midpoint)) + 1); } - void verify(const accel_args& args) const { - if (args.limit <= 1) bad_arg("exponent must be greater than 1"); - if (args.midpoint < 0) bad_arg("midpoint must not be negative"); - } }; + using accel_sigmoid = additive_accel<sigmoid_impl>; + } diff --git a/common/accel-sigmoidgain.hpp b/common/accel-sigmoidgain.hpp index 0a2e54d..99bb146 100644 --- a/common/accel-sigmoidgain.hpp +++ b/common/accel-sigmoidgain.hpp @@ -7,31 +7,27 @@ namespace rawaccel { /// <summary> Struct to hold sigmoid (s-shaped) gain implementation. </summary> - struct accel_sigmoidgain : accel_base { - double limit = 1; - double midpoint = 0; - double additive_constant = 0; - double integration_constant = 0; - - accel_sigmoidgain(const accel_args& args) : accel_base(args) { - verify(args); - - limit = args.limit - 1; - midpoint = args.midpoint; - additive_constant = exp(speed_coeff*midpoint); + struct sigmoidgain_impl { + double rate; + double limit; + double additive_constant; + double integration_constant; + + sigmoidgain_impl(const accel_args& args) : + rate(args.rate), limit(args.limit - 1) + { + additive_constant = exp(rate * args.midpoint); integration_constant = log(1 + additive_constant); } - inline double accelerate(double speed) const { + inline double operator()(double speed) const { //f(x) = k/(1+e^(-m(c-x))) - double scaled_speed = speed_coeff * speed; + double scaled_speed = rate * speed; return limit * ((log(additive_constant+exp(scaled_speed)) - integration_constant)/scaled_speed); } - void verify(const accel_args& args) const { - if (args.limit <= 1) bad_arg("exponent must be greater than 1"); - if (args.midpoint < 0) bad_arg("midpoint must not be negative"); - } }; + using accel_sigmoidgain = additive_accel<sigmoidgain_impl>; + } diff --git a/common/common.vcxitems b/common/common.vcxitems index 2e9265c..52d4f8a 100644 --- a/common/common.vcxitems +++ b/common/common.vcxitems @@ -26,8 +26,8 @@ <ClInclude Include="$(MSBuildThisFileDirectory)accel-sigmoidgain.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)rawaccel-error.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)rawaccel-io.hpp" /> + <ClInclude Include="$(MSBuildThisFileDirectory)rawaccel-settings.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)rawaccel.hpp" /> - <ClInclude Include="$(MSBuildThisFileDirectory)tagged-union-single.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)x64-util.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)vec2.h" /> </ItemGroup> diff --git a/common/rawaccel-io.hpp b/common/rawaccel-io.hpp index 7f55392..74e2d1e 100644 --- a/common/rawaccel-io.hpp +++ b/common/rawaccel-io.hpp @@ -5,7 +5,8 @@ #define NOMINMAX #include <Windows.h> -#include "rawaccel.hpp" +#include "rawaccel-settings.h" +#include "rawaccel-error.hpp" #define RA_READ CTL_CODE(0x8888, 0x888, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) #define RA_WRITE CTL_CODE(0x8888, 0x889, METHOD_BUFFERED, FILE_ANY_ACCESS) @@ -15,7 +16,7 @@ namespace rawaccel { - mouse_modifier read() { + settings read() { HANDLE ra_handle = INVALID_HANDLE_VALUE; ra_handle = CreateFileW(L"\\\\.\\rawaccel", 0, 0, 0, OPEN_EXISTING, 0, 0); @@ -24,7 +25,7 @@ namespace rawaccel { throw install_error(); } - mouse_modifier mod; + settings args; DWORD dummy; BOOL success = DeviceIoControl( @@ -32,8 +33,8 @@ namespace rawaccel { RA_READ, NULL, // input buffer 0, // input buffer size - &mod, // output buffer - sizeof(mouse_modifier), // output buffer size + &args, // output buffer + sizeof(settings), // output buffer size &dummy, // bytes returned NULL // overlapped structure ); @@ -44,11 +45,11 @@ namespace rawaccel { throw std::system_error(GetLastError(), std::system_category(), "DeviceIoControl failed"); } - return mod; + return args; } - void write(mouse_modifier mod) { + void write(const settings& args) { HANDLE ra_handle = INVALID_HANDLE_VALUE; ra_handle = CreateFileW(L"\\\\.\\rawaccel", 0, 0, 0, OPEN_EXISTING, 0, 0); @@ -62,12 +63,12 @@ namespace rawaccel { BOOL success = DeviceIoControl( ra_handle, RA_WRITE, - &mod, // input buffer - sizeof(mouse_modifier), // input buffer size - NULL, // output buffer - 0, // output buffer size - &dummy, // bytes returned - NULL // overlapped structure + const_cast<settings*>(&args), // input buffer + sizeof(settings), // input buffer size + NULL, // output buffer + 0, // output buffer size + &dummy, // bytes returned + NULL // overlapped structure ); CloseHandle(ra_handle); diff --git a/common/rawaccel-settings.h b/common/rawaccel-settings.h new file mode 100644 index 0000000..b9ff946 --- /dev/null +++ b/common/rawaccel-settings.h @@ -0,0 +1,21 @@ +#pragma once + +#include "vec2.h" +#include "accel-base.hpp" + +namespace rawaccel { + + enum class accel_mode { + linear, classic, natural, logarithmic, sigmoid, naturalgain, sigmoidgain, power, noaccel + }; + + struct settings { + double degrees_rotation = 0; + bool combine_mags = true; + vec2<accel_mode> modes = { accel_mode::noaccel, accel_mode::noaccel }; + vec2<accel_args> argsv; + vec2d sens = { 1, 1 }; + double time_min = 0.4; + }; + +} diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp index 23a8214..d3a2a03 100644 --- a/common/rawaccel.hpp +++ b/common/rawaccel.hpp @@ -3,8 +3,8 @@ #define _USE_MATH_DEFINES #include <math.h> +#include "rawaccel-settings.h" #include "x64-util.hpp" -#include "tagged-union-single.h" #include "accel-linear.hpp" #include "accel-classic.hpp" @@ -31,7 +31,7 @@ namespace rawaccel { /// </summary> /// <param name="input">Input vector to be rotated</param> /// <returns>2d vector of rotated input.</returns> - inline vec2d operator()(const vec2d& input) const { + inline vec2d apply(const vec2d& input) const { return { input.x * rot_vec.x - input.y * rot_vec.y, input.x * rot_vec.y + input.y * rot_vec.x @@ -60,7 +60,7 @@ namespace rawaccel { return clampsd(scale, lo, hi); } - accel_scale_clamp(double cap) : accel_scale_clamp() { + accel_scale_clamp(double cap) { if (cap <= 0) { // use default, effectively uncapped accel return; @@ -76,9 +76,53 @@ namespace rawaccel { accel_scale_clamp() = default; }; + + template <typename Visitor, typename Variant> + inline auto visit_accel(Visitor vis, Variant&& var) { + switch (var.tag) { + case accel_mode::linear: return vis(var.u.linear); + case accel_mode::classic: return vis(var.u.classic); + case accel_mode::natural: return vis(var.u.natural); + case accel_mode::logarithmic: return vis(var.u.logarithmic); + case accel_mode::sigmoid: return vis(var.u.sigmoid); + case accel_mode::naturalgain: return vis(var.u.naturalgain); + case accel_mode::sigmoidgain: return vis(var.u.sigmoidgain); + case accel_mode::power: return vis(var.u.power); + default: return vis(var.u.noaccel); + } + } + + struct accel_variant { + accel_mode tag = accel_mode::noaccel; + + union union_t { + accel_linear linear; + accel_classic classic; + accel_natural natural; + accel_logarithmic logarithmic; + accel_sigmoid sigmoid; + accel_naturalgain naturalgain; + accel_sigmoidgain sigmoidgain; + accel_power power; + accel_noaccel noaccel = {}; + } u = {}; + + accel_variant(const accel_args& args, accel_mode mode) : + tag(mode) + { + visit_accel([&](auto& impl) { + impl = { args }; + }, *this); + } - /// <summary> Tagged union to hold all accel implementations and allow "polymorphism" via a visitor call. </summary> - using accel_impl_t = tagged_union<accel_linear, accel_classic, accel_natural, accel_logarithmic, accel_sigmoid, accel_power, accel_naturalgain, accel_sigmoidgain, accel_noaccel>; + inline double apply(double speed) const { + return visit_accel([=](auto&& impl) { + return impl(speed); + }, *this); + } + + accel_variant() = default; + }; /// <summary> Struct to hold information about applying a gain cap. </summary> struct velocity_gain_cap { @@ -92,18 +136,14 @@ namespace rawaccel { // <summary> The intercept for the line with above slope to give continuous velocity function </summary> double intercept = 0; - // <summary> Whether or not velocity gain cap is enabled </summary> - bool cap_gain_enabled = false; - /// <summary> /// Initializes a velocity gain cap for a certain speed threshold /// by estimating the slope at the threshold and creating a line /// with that slope for output velocity calculations. /// </summary> /// <param name="speed"> The speed at which velocity gain cap will kick in </param> - /// <param name="offset"> The offset applied in accel calculations </param> - /// <param name="accel"> The accel implementation used in the containing accel_fn </param> - velocity_gain_cap(double speed, double offset, accel_impl_t accel) + /// <param name="accel"> The accel implementation used in the containing accel_variant </param> + velocity_gain_cap(double speed, const accel_variant& accel) { if (speed <= 0) return; @@ -115,18 +155,9 @@ namespace rawaccel { // Return if by glitch or strange values the difference in points is 0. if (speed_diff == 0) return; - cap_gain_enabled = true; - // Find the corresponding output velocities for the two points. - // Subtract offset for acceleration, like in accel_fn() - double out_first = accel.visit([=](auto&& impl) { - double accel_val = impl.accelerate(speed-offset); - return impl.scale(accel_val); - }).x * speed; - double out_second = accel.visit([=](auto&& impl) { - double accel_val = impl.accelerate(speed_second-offset); - return impl.scale(accel_val); - }).x * speed_second; + double out_first = accel.apply(speed) * speed; + double out_second = accel.apply(speed_second) * speed_second; // Calculate slope and intercept from two points. slope = (out_second - out_first) / speed_diff; @@ -141,7 +172,7 @@ namespace rawaccel { /// </summary> /// <param name="speed"> Speed to be capped </param> /// <returns> Scale multiplier for input </returns> - inline double operator()(double speed) const { + inline double apply(double speed) const { return slope + intercept / speed; } @@ -151,166 +182,97 @@ namespace rawaccel { /// <param name="speed"> Speed to check against threshold. </param> /// <returns> Whether gain cap should be applied. </returns> inline bool should_apply(double speed) const { - return cap_gain_enabled && speed > threshold; + return threshold > 0 && speed > threshold; } velocity_gain_cap() = default; }; - struct accel_fn_args { - accel_args acc_args; - int accel_mode = accel_impl_t::id<accel_noaccel>; - milliseconds time_min = 0.4; - vec2d cap = { 0, 0 }; - }; - - /// <summary> Struct for holding acceleration application details. </summary> - struct accel_function { - - /* - This value is ideally a few microseconds lower than - the user's mouse polling interval, though it should - not matter if the system is stable. - */ - /// <summary> The minimum time period for one mouse movement. </summary> - milliseconds time_min = 0.4; - - /// <summary> The offset past which acceleration is applied. </summary> - double speed_offset = 0; + struct accelerator { + accel_variant accel; + velocity_gain_cap gain_cap; + accel_scale_clamp clamp; - /// <summary> The acceleration implementation (i.e. curve) </summary> - accel_impl_t accel; + accelerator(const accel_args& args, accel_mode mode) : + accel(args, mode), gain_cap(args.gain_cap, accel), clamp(args.scale_cap) + {} - /// <summary> The object which sets a min and max for the acceleration scale. </summary> - vec2<accel_scale_clamp> clamp; - - velocity_gain_cap gain_cap = velocity_gain_cap(); - - accel_args impl_args; - - accel_function(const accel_fn_args& args) { - if (args.time_min <= 0) bad_arg("min time must be positive"); - if (args.acc_args.offset < 0) bad_arg("offset must not be negative"); - - accel.tag = args.accel_mode; - accel.visit([&](auto& impl) { impl = { args.acc_args }; }); - impl_args = args.acc_args; - - time_min = args.time_min; - speed_offset = args.acc_args.offset; - clamp.x = accel_scale_clamp(args.cap.x); - clamp.y = accel_scale_clamp(args.cap.y); - gain_cap = velocity_gain_cap(args.acc_args.gain_cap, speed_offset, accel); - } - - /// <summary> - /// Applies weighted acceleration to given input for given time period. - /// </summary> - /// <param name="input">2d vector of {x, y} mouse movement to be accelerated</param> - /// <param name="time">Time period over which input movement was accumulated</param> - /// <returns></returns> - inline vec2d operator()(const vec2d& input, milliseconds time) const { - double mag = sqrtsd(input.x * input.x + input.y * input.y); - double time_clamped = clampsd(time, time_min, 100); - double raw_speed = mag / time_clamped; - - vec2d scale; - - // gain_cap needs raw speed for velocity line calculation - if (gain_cap.should_apply(raw_speed)) - { - double gain_cap_scale = gain_cap(raw_speed); - scale = { gain_cap_scale, gain_cap_scale }; + inline double apply(double speed) const { + if (gain_cap.should_apply(speed)) { + return clamp(gain_cap.apply(speed)); } - else - { - scale = accel.visit([=](auto&& impl) { - double accel_val = impl.accelerate(maxsd(mag / time_clamped - speed_offset, 0)); - return impl.scale(accel_val); - }); - } - - return { - input.x * clamp.x(scale.x), - input.y * clamp.y(scale.y) - }; + else return clamp(accel.apply(speed)); } - accel_function() = default; - }; - - struct modifier_args { - double degrees = 0; - vec2d sens = { 1, 1 }; - accel_fn_args acc_fn_args; + accelerator() = default; }; /// <summary> Struct to hold variables and methods for modifying mouse input </summary> struct mouse_modifier { bool apply_rotate = false; bool apply_accel = false; + bool combine_magnitudes = true; rotator rotate; - accel_function accel_fn; + vec2<accelerator> accels; vec2d sensitivity = { 1, 1 }; - mouse_modifier(const modifier_args& args) - : accel_fn(args.acc_fn_args) + mouse_modifier(const settings& args) : + combine_magnitudes(args.combine_mags) { - apply_rotate = args.degrees != 0; - - if (apply_rotate) rotate = rotator(args.degrees); - else rotate = rotator(); - - apply_accel = args.acc_fn_args.accel_mode != 0 && - args.acc_fn_args.accel_mode != accel_impl_t::id<accel_noaccel>; + if (args.degrees_rotation != 0) { + rotate = rotator(args.degrees_rotation); + apply_rotate = true; + } + + if (args.sens.x != 0) sensitivity.x = args.sens.x; + if (args.sens.y != 0) sensitivity.y = args.sens.y; - if (args.sens.x == 0) sensitivity.x = 1; - else sensitivity.x = args.sens.x; + if ((combine_magnitudes && args.modes.x == accel_mode::noaccel) || + (args.modes.x == accel_mode::noaccel && + args.modes.y == accel_mode::noaccel)) { + return; + } - if (args.sens.y == 0) sensitivity.y = 1; - else sensitivity.y = args.sens.y; + accels.x = accelerator(args.argsv.x, args.modes.x); + accels.y = accelerator(args.argsv.y, args.modes.y); + apply_accel = true; } - /// <summary> - /// Applies modification without acceleration. - /// </summary> - /// <param name="input">Input to be modified.</param> - /// <returns>2d vector of modified input.</returns> - inline vec2d modify_without_accel(vec2d input) - { - if (apply_rotate) - { - input = rotate(input); - } - - input.x *= sensitivity.x; - input.y *= sensitivity.y; + void modify(vec2d& movement, milliseconds time) { + apply_rotation(movement); + apply_acceleration(movement, [=] { return time; }); + apply_sensitivity(movement); + } - return input; + inline void apply_rotation(vec2d& movement) { + if (apply_rotate) movement = rotate.apply(movement); } - /// <summary> - /// Applies modification, including acceleration. - /// </summary> - /// <param name="input">Input to be modified</param> - /// <param name="time">Time period for determining acceleration.</param> - /// <returns>2d vector with modified input.</returns> - inline vec2d modify_with_accel(vec2d input, milliseconds time) - { - if (apply_rotate) - { - input = rotate(input); + template <typename TimeSupplier> + inline void apply_acceleration(vec2d& movement, TimeSupplier time_supp) { + if (apply_accel) { + milliseconds time = time_supp(); + + if (combine_magnitudes) { + double mag = sqrtsd(movement.x * movement.x + movement.y * movement.y); + double speed = mag / time; + double scale = accels.x.apply(speed); + movement.x *= scale; + movement.y *= scale; + } + else { + movement.x *= accels.x.apply(fabs(movement.x) / time); + movement.y *= accels.y.apply(fabs(movement.y) / time); + } } + } - input = accel_fn(input, time); - - input.x *= sensitivity.x; - input.y *= sensitivity.y; - - return input; + inline void apply_sensitivity(vec2d& movement) { + movement.x *= sensitivity.x; + movement.y *= sensitivity.y; } mouse_modifier() = default; }; -} // rawaccel
\ No newline at end of file +} // rawaccel diff --git a/common/tagged-union-single.h b/common/tagged-union-single.h deleted file mode 100644 index f0de097..0000000 --- a/common/tagged-union-single.h +++ /dev/null @@ -1,202 +0,0 @@ -#pragma once - -using size_t = decltype(alignof(char)); - -namespace type_traits { - -template< class T > struct remove_cv { typedef T type; }; -template< class T > struct remove_cv<const T> { typedef T type; }; -template< class T > struct remove_cv<volatile T> { typedef T type; }; -template< class T > struct remove_cv<const volatile T> { typedef T type; }; -template< class T > using remove_cv_t = typename remove_cv<T>::type; - -template< class T > struct remove_reference { typedef T type; }; -template< class T > struct remove_reference<T&> { typedef T type; }; -template< class T > struct remove_reference<T&&> { typedef T type; }; -template< class T > using remove_reference_t = typename remove_reference<T>::type; - -template< class T > -struct remove_cvref { - using type = remove_cv_t<remove_reference_t<T>>; -}; -template< class T > using remove_cvref_t = typename remove_cvref<T>::type; - -namespace detail { - -template <class T> struct type_identity { using type = T; }; - -template <class T> -auto try_add_lvalue_reference(int)->type_identity<T&>; -template <class T> -auto try_add_lvalue_reference(...)->type_identity<T>; - -template <class T> -auto try_add_rvalue_reference(int)->type_identity<T&&>; -template <class T> -auto try_add_rvalue_reference(...)->type_identity<T>; - -} // type_traits::detail - -template <class T> struct add_lvalue_reference : decltype(detail::try_add_lvalue_reference<T>(0)) {}; -template< class T > using add_lvalue_reference_t = typename add_lvalue_reference<T>::type; - -template <class T> struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference<T>(0)) {}; -template< class T > using add_rvalue_reference_t = typename add_rvalue_reference<T>::type; - -template <typename T, typename U> inline constexpr bool is_same_v = false; -template <typename T> inline constexpr bool is_same_v<T, T> = true; -template <typename T> inline constexpr bool is_void_v = is_same_v<remove_cv_t<T>, void>; - -} // type_traits - -template<class T> type_traits::add_rvalue_reference_t<T> declval() noexcept; - -template <typename T> -inline constexpr T maxv(const T& a, const T& b) { - return (b < a) ? a : b; -} - -template <typename T> -inline constexpr T minv(const T& a, const T& b) { - return (a < b) ? a : b; -} - -template <typename T> -inline constexpr T clampv(const T& v, const T& lo, const T& hi) { - return minv(maxv(v, lo), hi); -} - -template <typename T> -inline constexpr const T& select_ref(bool pred, const T& t, const T& f) { - return pred ? t : f; -} - -template <typename First, typename... Rest> -inline constexpr size_t max_size_of = maxv(sizeof(First), max_size_of<Rest...>); - -template <typename T> -inline constexpr size_t max_size_of<T> = sizeof(T); - -template <typename First, typename... Rest> -inline constexpr size_t max_align_of = maxv(alignof(First), max_align_of<Rest...>); - -template <typename T> -inline constexpr size_t max_align_of<T> = alignof(T); - -namespace detail { - -template <typename... Ts> -struct b1_index_of_impl { - - template <typename...> - struct idx { - static constexpr size_t value = 0; - }; - - template <typename T, typename First, typename... Rest> - struct idx <T, First, Rest...> { - static constexpr size_t value = []() { - if constexpr (type_traits::is_same_v<T, First>) { - return sizeof...(Ts) - sizeof...(Rest); - } - return idx<T, Rest...>::value; - }(); - }; -}; - -} // detail - -template <typename T, typename First, typename... Rest> -inline constexpr int base1_index_of = -detail::b1_index_of_impl<First, Rest...>::template idx<T, First, Rest...>::value; - -/* -Requirements: Every type is trivially-copyable and is not an array type - -Can be initialized to an empty state as if by using -std::variant<std::monostate, First, Rest...> -*/ -template <typename First, typename... Rest> -struct tagged_union { - - // Requirements: The return type of Visitor is default-constructible (or void) - // Returns a value-initialized object when in an empty or invalid state - template<typename Visitor> - inline constexpr auto visit(Visitor vis) { - return visit_impl<Visitor, First, Rest...>(vis); - } - - template<typename Visitor> - inline constexpr auto visit(Visitor vis) const { - return visit_impl<Visitor, First, Rest...>(vis); - } - - template<typename T> - static constexpr int id = base1_index_of<T, First, Rest...>; - - int tag = 0; - - struct storage_t { - alignas(max_align_of<First, Rest...>) char bytes[max_size_of<First, Rest...>] = {}; - - template <typename T> - inline constexpr T& as() { - static_assert(id<T> != 0, "tagged_union can not hold T"); - return reinterpret_cast<T&>(bytes); - } - - template <typename T> - inline constexpr const T& as() const { - static_assert(id<T> != 0, "tagged_union can not hold T"); - return reinterpret_cast<const T&>(bytes); - } - - } storage; - - constexpr tagged_union() noexcept = default; - - template<typename T> - inline constexpr tagged_union(const T& val) noexcept { - tag = id<T>; - storage.template as<T>() = val; - } - - template<typename T> - inline constexpr tagged_union& operator=(const T& val) noexcept { - tag = id<T>; - storage.template as<T>() = val; - return *this; - } - -private: - template<typename Visitor, typename T1, typename... TRest> - inline constexpr auto visit_impl(Visitor vis) const { - if (tag == id<T1>) { - return vis(storage.template as<T1>()); - } - if constexpr (sizeof...(TRest) > 0) { - return visit_impl<Visitor, TRest...>(vis); - } - else { - using ReturnType = decltype(vis(declval<First&>())); - if constexpr (!type_traits::is_void_v<ReturnType>) return ReturnType{}; - } - } - - template<typename Visitor, typename T1, typename... TRest> - inline constexpr auto visit_impl(Visitor vis) { - if (tag == id<T1>) { - return vis(storage.template as<T1>()); - } - if constexpr (sizeof...(TRest) > 0) { - return visit_impl<Visitor, TRest...>(vis); - } - else { - using ReturnType = decltype(vis(declval<First&>())); - if constexpr (!type_traits::is_void_v<ReturnType>) return ReturnType{}; - } - } -}; - -template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; }; -template<class... Ts> overloaded(Ts...)->overloaded<Ts...>; |