summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authora1xd <[email protected]>2020-07-31 05:12:04 -0400
committerGitHub <[email protected]>2020-07-31 05:12:04 -0400
commitd5c012bcd5b7321671f9591a3e58d0b2c9507467 (patch)
treefe64110f7678607947d19c5ba0b46ea2b15d69c4
parentMerge pull request #5 from JacobPalecki/WrapperAndGrapher (diff)
parentupdate grapher/wrapper for st-refactor (diff)
downloadrawaccel-d5c012bcd5b7321671f9591a3e58d0b2c9507467.tar.xz
rawaccel-d5c012bcd5b7321671f9591a3e58d0b2c9507467.zip
Merge pull request #6 from a1xd/st-refactor
Refactor
-rw-r--r--common/accel-base.hpp69
-rw-r--r--common/accel-classic.hpp29
-rw-r--r--common/accel-error.hpp11
-rw-r--r--common/accel-linear.hpp14
-rw-r--r--common/accel-logarithmic.hpp20
-rw-r--r--common/accel-natural.hpp31
-rw-r--r--common/accel-noaccel.hpp14
-rw-r--r--common/accel-power.hpp41
-rw-r--r--common/accel-sigmoid.hpp32
-rw-r--r--common/common.vcxitems9
-rw-r--r--common/external/nillable.h30
-rw-r--r--common/external/tagged-union-single.h202
-rw-r--r--common/rawaccel-userspace.hpp57
-rw-r--r--common/rawaccel.hpp350
-rw-r--r--common/x64-util.hpp10
-rw-r--r--console/console.cpp4
-rw-r--r--driver/driver.cpp26
-rw-r--r--grapher/Form1.cs71
-rw-r--r--wrapper/wrapper.cpp9
-rw-r--r--wrapper/wrapper.hpp38
20 files changed, 842 insertions, 225 deletions
diff --git a/common/accel-base.hpp b/common/accel-base.hpp
new file mode 100644
index 0000000..da2c96b
--- /dev/null
+++ b/common/accel-base.hpp
@@ -0,0 +1,69 @@
+#pragma once
+
+#include "vec2.h"
+
+namespace rawaccel {
+
+ // Error throwing calls std libraries which are unavailable in kernel mode.
+ void error(const char* s);
+
+ using milliseconds = double;
+
+ /// <summary> Struct to hold arguments for an acceleration function. </summary>
+ struct accel_args {
+ double offset = 0;
+ double accel = 0;
+ double limit = 2;
+ double exponent = 2;
+ double midpoint = 0;
+ double power_scale = 1;
+ vec2d weight = { 1, 1 };
+ };
+
+ /// <summary>
+ /// Struct to hold common acceleration curve implementation details.
+ /// </summary>
+ struct accel_base {
+
+ /// <summary> Coefficients applied to acceleration per axis.</summary>
+ vec2d weight = { 1, 1 };
+
+ /// <summary> Generally, the acceleration ramp rate.
+ double speed_coeff = 0;
+
+ accel_base(const accel_args& args) {
+ verify(args);
+
+ speed_coeff = args.accel;
+ weight = args.weight;
+ }
+
+ /// <summary>
+ /// Default transformation of speed -> acceleration.
+ /// </summary>
+ inline double accelerate(double speed) const {
+ return speed_coeff * speed;
+ }
+
+ /// <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
+ };
+ }
+
+ /// <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) error("accel can not be negative, use a negative weight to compensate");
+ }
+
+ accel_base() = default;
+ };
+
+}
diff --git a/common/accel-classic.hpp b/common/accel-classic.hpp
new file mode 100644
index 0000000..1a2adca
--- /dev/null
+++ b/common/accel-classic.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <math.h>
+
+#include "accel-base.hpp"
+
+namespace rawaccel {
+
+ /// <summary> Struct to hold "classic" (linear raised to power) acceleration implementation. </summary>
+ struct accel_classic : accel_base {
+ double exponent;
+
+ accel_classic(const accel_args& args) : accel_base(args) {
+ verify(args);
+
+ 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) error("exponent must be greater than 1");
+ }
+ };
+
+}
diff --git a/common/accel-error.hpp b/common/accel-error.hpp
new file mode 100644
index 0000000..fa1f999
--- /dev/null
+++ b/common/accel-error.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <stdexcept>
+
+namespace rawaccel {
+
+ void error(const char* s) {
+ throw std::domain_error(s);
+ }
+
+}
diff --git a/common/accel-linear.hpp b/common/accel-linear.hpp
new file mode 100644
index 0000000..5cbb7c6
--- /dev/null
+++ b/common/accel-linear.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "accel-base.hpp"
+
+namespace rawaccel {
+
+ /// <summary> Struct to hold linear acceleration implementation. </summary>
+ struct accel_linear : accel_base {
+
+ using accel_base::accel_base;
+
+ };
+
+}
diff --git a/common/accel-logarithmic.hpp b/common/accel-logarithmic.hpp
new file mode 100644
index 0000000..928eda9
--- /dev/null
+++ b/common/accel-logarithmic.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <math.h>
+
+#include "accel-base.hpp"
+
+namespace rawaccel {
+
+ /// <summary> Struct to hold logarithmic acceleration implementation. </summary>
+ struct accel_logarithmic : accel_base {
+
+ using accel_base::accel_base;
+
+ inline double accelerate(double speed) const {
+ //f(x) = log(m*x+1)
+ return log(speed_coeff * speed + 1);
+ }
+ };
+
+}
diff --git a/common/accel-natural.hpp b/common/accel-natural.hpp
new file mode 100644
index 0000000..c87fda8
--- /dev/null
+++ b/common/accel-natural.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <math.h>
+
+#include "accel-base.hpp"
+
+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;
+ }
+
+ inline double accelerate(double speed) const {
+ // f(x) = k(1-e^(-mx))
+ return limit - (limit * exp(-speed_coeff * speed));
+ }
+
+ void verify(const accel_args& args) const {
+ if (args.limit <= 1) error("limit must be greater than 1");
+ }
+ };
+
+}
diff --git a/common/accel-noaccel.hpp b/common/accel-noaccel.hpp
new file mode 100644
index 0000000..b7f730b
--- /dev/null
+++ b/common/accel-noaccel.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "accel-base.hpp"
+
+namespace rawaccel {
+
+ /// <summary> Struct to hold acceleration implementation which applies no acceleration. </summary>
+ struct accel_noaccel : accel_base {
+
+ accel_noaccel(const accel_args&) : accel_base() {}
+
+ };
+
+}
diff --git a/common/accel-power.hpp b/common/accel-power.hpp
new file mode 100644
index 0000000..7f4c220
--- /dev/null
+++ b/common/accel-power.hpp
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <math.h>
+
+#include "accel-base.hpp"
+
+namespace rawaccel {
+
+ /// <summary> Struct to hold power (non-additive) acceleration implementation. </summary>
+ struct accel_power : accel_base {
+ double exponent;
+ double offset;
+
+ accel_power(const accel_args& args) {
+ verify(args);
+
+ weight = args.weight;
+ speed_coeff = args.power_scale;
+ exponent = args.exponent;
+ offset = args.offset;
+ }
+
+ inline double accelerate(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) error("scale must be positive");
+ if (args.exponent <= 0) error("exponent must be greater than 0");
+ }
+ };
+
+}
diff --git a/common/accel-sigmoid.hpp b/common/accel-sigmoid.hpp
new file mode 100644
index 0000000..7cfa6c4
--- /dev/null
+++ b/common/accel-sigmoid.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <math.h>
+
+#include "accel-base.hpp"
+
+namespace rawaccel {
+
+ /// <summary> Struct to hold sigmoid (s-shaped) acceleration implementation. </summary>
+ struct accel_sigmoid : accel_base {
+ double limit = 1;
+ double midpoint = 0;
+
+ accel_sigmoid(const accel_args& args) : accel_base(args) {
+ verify(args);
+
+ limit = args.limit - 1;
+ midpoint = args.midpoint;
+ }
+
+ inline double accelerate(double speed) const {
+ //f(x) = k/(1+e^(-m(c-x)))
+ return limit / (exp(-speed_coeff * (speed - midpoint)) + 1);
+ }
+
+ void verify(const accel_args& args) const {
+ if (args.limit <= 1) error("exponent must be greater than 1");
+ if (args.midpoint < 0) error("midpoint must not be negative");
+ }
+ };
+
+}
diff --git a/common/common.vcxitems b/common/common.vcxitems
index f60f78a..d1e8db0 100644
--- a/common/common.vcxitems
+++ b/common/common.vcxitems
@@ -14,6 +14,15 @@
<ProjectCapability Include="SourceItemsFromImports" />
</ItemGroup>
<ItemGroup>
+ <ClInclude Include="$(MSBuildThisFileDirectory)accel-base.hpp" />
+ <ClInclude Include="$(MSBuildThisFileDirectory)accel-classic.hpp" />
+ <ClInclude Include="$(MSBuildThisFileDirectory)accel-linear.hpp" />
+ <ClInclude Include="$(MSBuildThisFileDirectory)accel-logarithmic.hpp" />
+ <ClInclude Include="$(MSBuildThisFileDirectory)accel-natural.hpp" />
+ <ClInclude Include="$(MSBuildThisFileDirectory)accel-noaccel.hpp" />
+ <ClInclude Include="$(MSBuildThisFileDirectory)accel-power.hpp" />
+ <ClInclude Include="$(MSBuildThisFileDirectory)accel-sigmoid.hpp" />
+ <ClInclude Include="$(MSBuildThisFileDirectory)accel-error.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)rawaccel-userspace.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)rawaccel.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)x64-util.hpp" />
diff --git a/common/external/nillable.h b/common/external/nillable.h
new file mode 100644
index 0000000..40cf01c
--- /dev/null
+++ b/common/external/nillable.h
@@ -0,0 +1,30 @@
+inline constexpr struct nil_t {} nil;
+
+// Requirements: T is default-constructible and trivially-destructible
+template<typename T>
+struct nillable {
+ bool has_value = false;
+ T value;
+
+ nillable() = default;
+
+ nillable(nil_t) : nillable() {}
+ nillable(const T& v) : has_value(true), value(v) {}
+
+ nillable& operator=(nil_t) {
+ has_value = false;
+ return *this;
+ }
+ nillable& operator=(const T& v) {
+ value = v;
+ has_value = true;
+ return *this;
+ }
+
+ const T* operator->() const { return &value; }
+ T* operator->() { return &value; }
+
+ explicit operator bool() const { return has_value; }
+};
+
+template<typename T> nillable(T)->nillable<T>;
diff --git a/common/external/tagged-union-single.h b/common/external/tagged-union-single.h
new file mode 100644
index 0000000..3353325
--- /dev/null
+++ b/common/external/tagged-union-single.h
@@ -0,0 +1,202 @@
+#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...>;
diff --git a/common/rawaccel-userspace.hpp b/common/rawaccel-userspace.hpp
index db50b35..c80262c 100644
--- a/common/rawaccel-userspace.hpp
+++ b/common/rawaccel-userspace.hpp
@@ -4,6 +4,7 @@
#include "external/clipp.h"
+#include "accel-error.hpp"
#include "rawaccel.hpp"
namespace rawaccel {
@@ -12,14 +13,14 @@ inline constexpr int SYSTEM_ERROR = -1;
inline constexpr int PARSE_ERROR = 1;
inline constexpr int INVALID_ARGUMENT = 2;
-void error(const char* s) {
- throw std::domain_error(s);
+template<typename Accel, typename StrFirst, typename... StrRest>
+clipp::parameter make_accel_cmd(modifier_args& args, StrFirst&& first_flag, StrRest&&... rest) {
+ return clipp::command(first_flag, rest...)
+ .set(args.acc_fn_args.accel_mode, accel_impl_t::id<Accel>);
}
-variables parse(int argc, char** argv) {
- double degrees = 0;
- vec2d sens = { 1, 1 };
- accel_function::args_t accel_args{};
+mouse_modifier parse(int argc, char** argv) {
+ modifier_args args{};
auto make_opt_vec = [](vec2d& v, auto first_flag, auto... rest) {
return clipp::option(first_flag, rest...) & (
@@ -40,64 +41,64 @@ variables parse(int argc, char** argv) {
};
// default options
- auto opt_sens = "sensitivity (default = 1)" % make_opt_vec(sens, "sens");
+ auto opt_sens = "sensitivity (default = 1)" % make_opt_vec(args.sens, "sens");
auto opt_rot = "counter-clockwise rotation (default = 0)" % (
clipp::option("rotate") &
- clipp::number("degrees", degrees)
+ clipp::number("degrees", args.degrees)
);
// mode-independent accel options
auto opt_weight = "accel multiplier (default = 1)" %
- make_opt_vec(accel_args.weight, "weight");
+ make_opt_vec(args.acc_fn_args.acc_args.weight, "weight");
auto opt_offset = "speed (dots/ms) where accel kicks in (default = 0)" % (
- clipp::option("offset") & clipp::number("speed", accel_args.offset)
+ clipp::option("offset") & clipp::number("speed", args.acc_fn_args.acc_args.offset)
);
auto opt_cap = "accel scale cap (default = 9)" %
- make_opt_vec(accel_args.cap, "cap");
+ make_opt_vec(args.acc_fn_args.cap, "cap");
auto opt_tmin = "minimum time between polls (default = 0.4)" % (
clipp::option("tmin") &
- clipp::number("ms", accel_args.time_min)
+ clipp::number("ms", args.acc_fn_args.time_min)
);
- auto accel_var = (clipp::required("accel") & clipp::number("num", accel_args.accel)) % "ramp rate";
- auto limit_var = (clipp::required("limit") & clipp::number("scale", accel_args.lim_exp)) % "limit";
+ auto accel_var = (clipp::required("accel") & clipp::number("num", args.acc_fn_args.acc_args.accel)) % "ramp rate";
+ auto limit_var = (clipp::required("limit") & clipp::number("scale", args.acc_fn_args.acc_args.limit)) % "limit";
+ auto exp_var = (clipp::required("exponent") & clipp::number("num", args.acc_fn_args.acc_args.exponent)) % "exponent";
// modes
- auto noaccel_mode = "no-accel mode" % (
- clipp::command("off", "noaccel").set(accel_args.accel_mode, mode::noaccel)
- );
+ auto noaccel_mode = "no-accel mode" % make_accel_cmd<accel_noaccel>(args, "off", "noaccel");
+
auto lin_mode = "linear accel mode:" % (
- clipp::command("linear").set(accel_args.accel_mode, mode::linear),
+ make_accel_cmd<accel_linear>(args, "linear"),
accel_var
);
auto classic_mode = "classic accel mode:" % (
- clipp::command("classic").set(accel_args.accel_mode, mode::classic),
+ make_accel_cmd<accel_classic>(args, "classic"),
accel_var,
- (clipp::required("exponent") & clipp::number("num", accel_args.lim_exp)) % "exponent"
+ exp_var
);
auto nat_mode = "natural accel mode:" % (
- clipp::command("natural").set(accel_args.accel_mode, mode::natural),
+ make_accel_cmd<accel_natural>(args, "natural"),
accel_var,
limit_var
);
auto log_mode = "logarithmic accel mode:" % (
- clipp::command("logarithmic").set(accel_args.accel_mode, mode::logarithmic),
+ make_accel_cmd<accel_logarithmic>(args, "logarithmic"),
accel_var
);
auto sig_mode = "sigmoid accel mode:" % (
- clipp::command("sigmoid").set(accel_args.accel_mode, mode::sigmoid),
+ make_accel_cmd<accel_sigmoid>(args, "sigmoid"),
accel_var,
limit_var,
- (clipp::required("midpoint") & clipp::number("speed", accel_args.midpoint)) % "midpoint"
+ (clipp::required("midpoint") & clipp::number("speed", args.acc_fn_args.acc_args.midpoint)) % "midpoint"
);
auto pow_mode = "power accel mode:" % (
- clipp::command("power").set(accel_args.accel_mode, mode::power) >> [&] { accel_args.accel = 1; },
- (clipp::required("exponent") & clipp::number("num", accel_args.lim_exp)) % "exponent",
- (clipp::option("scale") & clipp::number("num", accel_args.accel)) % "scale factor"
+ make_accel_cmd<accel_power>(args, "power"),
+ exp_var,
+ (clipp::option("scale") & clipp::number("num", args.acc_fn_args.acc_args.power_scale)) % "scale factor"
);
auto accel_mode_exclusive = (lin_mode | classic_mode | nat_mode | log_mode | sig_mode | pow_mode);
@@ -121,7 +122,7 @@ variables parse(int argc, char** argv) {
std::exit(0);
}
- return variables(-degrees, sens, accel_args);
+ return mouse_modifier(args);
}
} // rawaccel
diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp
index 095af76..59a0360 100644
--- a/common/rawaccel.hpp
+++ b/common/rawaccel.hpp
@@ -3,178 +3,216 @@
#define _USE_MATH_DEFINES
#include <math.h>
-#include "vec2.h"
#include "x64-util.hpp"
+#include "external/tagged-union-single.h"
+
+#include "accel-linear.hpp"
+#include "accel-classic.hpp"
+#include "accel-natural.hpp"
+#include "accel-logarithmic.hpp"
+#include "accel-sigmoid.hpp"
+#include "accel-power.hpp"
+#include "accel-noaccel.hpp"
+
+namespace rawaccel {
+
+ /// <summary> Struct to hold vector rotation details. </summary>
+ struct rotator {
+
+ /// <summary> Rotational vector, which points in the direction of the post-rotation positive x axis. </summary>
+ vec2d rot_vec = { 1, 0 };
+
+ /// <summary>
+ /// Rotates given input vector according to struct's rotational vector.
+ /// </summary>
+ /// <param name="input">Input vector to be rotated</param>
+ /// <returns>2d vector of rotated input.</returns>
+ inline vec2d operator()(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
+ };
+ }
+
+ rotator(double degrees) {
+ double rads = degrees * M_PI / 180;
+ rot_vec = { cos(rads), sin(rads) };
+ }
+
+ rotator() = default;
+ };
+
+ /// <summary> Struct to hold clamp (min and max) details for acceleration application </summary>
+ struct accel_scale_clamp {
+ double lo = 0;
+ double hi = 9;
+
+ /// <summary>
+ /// Clamps given input to min at lo, max at hi.
+ /// </summary>
+ /// <param name="scale">Double to be clamped</param>
+ /// <returns>Clamped input as double</returns>
+ inline double operator()(double scale) const {
+ return clampsd(scale, lo, hi);
+ }
+
+ accel_scale_clamp(double cap) : accel_scale_clamp() {
+ if (cap <= 0) {
+ // use default, effectively uncapped accel
+ return;
+ }
+
+ if (cap < 1) {
+ // assume negative accel
+ lo = cap;
+ hi = 1;
+ }
+ else hi = cap;
+ }
-namespace rawaccel {
+ accel_scale_clamp() = default;
+ };
-enum class mode { noaccel, linear, classic, natural, logarithmic, sigmoid, power };
+ /// <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_noaccel>;
-struct rotator {
- vec2d rot_vec = { 1, 0 };
+ 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 };
+ };
- inline vec2d operator()(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
- };
- }
+ /// <summary> Struct for holding acceleration application details. </summary>
+ struct accel_function {
- rotator(double degrees) {
- double rads = degrees * M_PI / 180;
- rot_vec = { cos(rads), sin(rads) };
- }
+ /*
+ 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;
- rotator() = default;
-};
+ /// <summary> The offset past which acceleration is applied. </summary>
+ double speed_offset = 0;
-struct accel_scale_clamp {
- double lo = 0;
- double hi = 9;
+ /// <summary> The acceleration implementation (i.e. curve) </summary>
+ accel_impl_t accel;
- inline double operator()(double scale) const {
- return clampsd(scale, lo, hi);
- }
+ /// <summary> The object which sets a min and max for the acceleration scale. </summary>
+ vec2<accel_scale_clamp> clamp;
- accel_scale_clamp(double cap) : accel_scale_clamp() {
- if (cap <= 0) {
- // use default, effectively uncapped accel
- return;
- }
+ accel_function(const accel_fn_args& args) {
+ if (args.time_min <= 0) error("min time must be positive");
+ if (args.acc_args.offset < 0) error("offset must not be negative");
- if (cap < 1) {
- // assume negative accel
- lo = cap;
- hi = 1;
- }
- else hi = cap;
- }
-
- accel_scale_clamp() = default;
-};
-
-void error(const char*);
-
-struct accel_function {
- using milliseconds = double;
-
- /*
- 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.
- */
- milliseconds time_min = 0.4;
-
- double speed_offset = 0;
-
- // speed midpoint in sigmoid mode
- double m = 0;
-
- // accel ramp rate
- double b = 0;
-
- // the limit for natural and sigmoid modes
- // or the exponent for classic and power modes
- double k = 1;
-
- vec2d weight = { 1, 1 };
- vec2<accel_scale_clamp> clamp;
-
- inline vec2d operator()(const vec2d& input, milliseconds time, mode accel_mode) const {
- double mag = sqrtsd(input.x * input.x + input.y * input.y);
- double time_clamped = clampsd(time, time_min, 100);
- double speed = maxsd(mag / time_clamped - speed_offset, 0);
-
- double accel_val = 0;
-
- switch (accel_mode) {
- case mode::linear: accel_val = b * speed;
- break;
- case mode::classic: accel_val = pow(b * speed, k);
- break;
- case mode::natural: accel_val = k - (k * exp(-b * speed));
- break;
- case mode::logarithmic: accel_val = log(speed * b + 1);
- break;
- case mode::sigmoid: accel_val = k / (exp(-b * (speed - m)) + 1);
- break;
- case mode::power: accel_val = (speed_offset > 0 && speed < 1) ? 0 : pow(speed*b, k) - 1;
- break;
- default:
- break;
+ accel.tag = args.accel_mode;
+ accel.visit([&](auto& impl){ impl = { 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);
}
- double scale_x = weight.x * accel_val + 1;
- double scale_y = weight.y * accel_val + 1;
+ /// <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 speed = maxsd(mag / time_clamped - speed_offset, 0);
+
+ vec2d scale = accel.visit([=](auto&& impl) {
+ double accel_val = impl.accelerate(speed);
+ return impl.scale(accel_val);
+ });
+
+ return {
+ input.x * clamp.x(scale.x),
+ input.y * clamp.y(scale.y)
+ };
+ }
- return {
- input.x * clamp.x(scale_x),
- input.y * clamp.y(scale_y)
- };
- }
+ accel_function() = default;
+ };
- struct args_t {
- mode accel_mode = mode::noaccel;
- milliseconds time_min = 0.4;
- double offset = 0;
- double accel = 0;
- double lim_exp = 2;
- double midpoint = 0;
- vec2d weight = { 1, 1 };
- vec2d cap = { 0, 0 };
+ struct modifier_args {
+ double degrees = 0;
+ vec2d sens = { 1, 1 };
+ accel_fn_args acc_fn_args;
};
- accel_function(args_t args) {
- // Preconditions to guard against division by zero and
- // ensure the C math functions can not return NaN or -Inf.
- if (args.accel < 0) error("accel can not be negative, use a negative weight to compensate");
- if (args.time_min <= 0) error("min time must be positive");
- if (args.lim_exp <= 1) {
- if (args.accel_mode == mode::classic) error("exponent must be greater than 1");
- if (args.accel_mode == mode::power) { if (args.lim_exp <=0 ) error("exponent must be greater than 0"); }
- else error("limit must be greater than 1");
+ /// <summary> Struct to hold variables and methods for modifying mouse input </summary>
+ struct mouse_modifier {
+ bool apply_rotate = false;
+ bool apply_accel = false;
+ rotator rotate;
+ accel_function accel_fn;
+ vec2d sensitivity = { 1, 1 };
+
+ mouse_modifier(const modifier_args& args)
+ : accel_fn(args.acc_fn_args)
+ {
+ 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.sens.x == 0) sensitivity.x = 1;
+ else sensitivity.x = args.sens.x;
+
+ if (args.sens.y == 0) sensitivity.y = 1;
+ else sensitivity.y = args.sens.y;
+ }
+
+ /// <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;
+
+ return input;
}
- time_min = args.time_min;
- m = args.midpoint;
- b = args.accel;
- k = args.lim_exp - 1;
- if (args.accel_mode == mode::natural) b /= k;
- if (args.accel_mode == mode::power) k++;
-
- speed_offset = args.offset;
- weight = args.weight;
- clamp.x = accel_scale_clamp(args.cap.x);
- clamp.y = accel_scale_clamp(args.cap.y);
- }
-
- accel_function() = default;
-};
-
-struct variables {
- bool apply_rotate = false;
- bool apply_accel = false;
- mode accel_mode = mode::noaccel;
- rotator rotate;
- accel_function accel_fn;
- vec2d sensitivity = { 1, 1 };
-
- variables(double degrees, vec2d sens, accel_function::args_t accel_args)
- : accel_fn(accel_args)
- {
- apply_rotate = degrees != 0;
- if (apply_rotate) rotate = rotator(degrees);
- else rotate = rotator();
-
- apply_accel = accel_args.accel_mode != mode::noaccel;
- accel_mode = accel_args.accel_mode;
-
- if (sens.x == 0) sens.x = 1;
- if (sens.y == 0) sens.y = 1;
- sensitivity = sens;
- }
-
- variables() = default;
-};
-
-} // rawaccel
+ /// <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);
+ }
+
+ input = accel_fn(input, time);
+
+ input.x *= sensitivity.x;
+ input.y *= sensitivity.y;
+
+ return input;
+ }
+
+ mouse_modifier() = default;
+ };
+
+} // rawaccel \ No newline at end of file
diff --git a/common/x64-util.hpp b/common/x64-util.hpp
index 2fb61bb..40bc7c4 100644
--- a/common/x64-util.hpp
+++ b/common/x64-util.hpp
@@ -1,7 +1,13 @@
#pragma once
-#include <emmintrin.h>
+#ifdef _MANAGED
+
+#include <math.h>
+inline double sqrtsd(double val) { return sqrt(val); }
+
+#else
+#include <emmintrin.h>
inline double sqrtsd(double val) {
__m128d src = _mm_load_sd(&val);
__m128d dst = _mm_sqrt_sd(src, src);
@@ -9,6 +15,8 @@ inline double sqrtsd(double val) {
return val;
}
+#endif
+
inline constexpr double minsd(double a, double b) {
return (a < b) ? a : b;
}
diff --git a/console/console.cpp b/console/console.cpp
index 6606cac..490051c 100644
--- a/console/console.cpp
+++ b/console/console.cpp
@@ -9,7 +9,7 @@
namespace ra = rawaccel;
-void write(ra::variables vars) {
+void write(ra::mouse_modifier vars) {
HANDLE ra_handle = INVALID_HANDLE_VALUE;
ra_handle = CreateFileW(L"\\\\.\\rawaccel", 0, 0, 0, OPEN_EXISTING, 0, 0);
@@ -24,7 +24,7 @@ void write(ra::variables vars) {
ra_handle,
RA_WRITE,
&vars,
- sizeof(ra::variables),
+ sizeof(ra::mouse_modifier),
NULL, // output buffer
0, // output buffer size
&dummy, // bytes returned
diff --git a/driver/driver.cpp b/driver/driver.cpp
index e77ac5f..1f9cebd 100644
--- a/driver/driver.cpp
+++ b/driver/driver.cpp
@@ -15,7 +15,7 @@ using milliseconds = double;
struct {
milliseconds tick_interval = 0; // set in DriverEntry
- ra::variables vars;
+ ra::mouse_modifier modifier;
} global;
VOID
@@ -69,25 +69,25 @@ Arguments:
static_cast<double>(it->LastY)
};
- if (global.vars.apply_rotate) {
- input = global.vars.rotate(input);
- }
-
- if (global.vars.apply_accel && local_apply_accel) {
+ if (global.modifier.apply_accel && local_apply_accel) {
auto now = KeQueryPerformanceCounter(NULL).QuadPart;
auto ticks = now - devExt->counter.QuadPart;
devExt->counter.QuadPart = now;
milliseconds time = ticks * global.tick_interval;
- if (time < global.vars.accel_fn.time_min) {
+ if (time < global.modifier.accel_fn.time_min) {
DebugPrint(("RA time < min with %d ticks\n", ticks));
}
- input = global.vars.accel_fn(input, time, global.vars.accel_mode);
+ input = global.modifier.modify_with_accel(input, time);
+ }
+ else
+ {
+ input = global.modifier.modify_without_accel(input);
}
- double result_x = input.x * global.vars.sensitivity.x + local_carry.x;
- double result_y = input.y * global.vars.sensitivity.y + local_carry.y;
+ double result_x = input.x + local_carry.x;
+ double result_y = input.y + local_carry.y;
LONG out_x = static_cast<LONG>(result_x);
LONG out_y = static_cast<LONG>(result_y);
@@ -154,7 +154,7 @@ Return Value:
DebugPrint(("Ioctl received into filter control object.\n"));
- if (InputBufferLength != sizeof(ra::variables)) {
+ if (InputBufferLength != sizeof(ra::mouse_modifier)) {
DebugPrint(("Received unknown request of %u bytes\n", InputBufferLength));
// status maps to win32 error code 1784: ERROR_INVALID_USER_BUFFER
WdfRequestComplete(Request, STATUS_INVALID_BUFFER_SIZE);
@@ -163,7 +163,7 @@ Return Value:
status = WdfRequestRetrieveInputBuffer(
Request,
- sizeof(ra::variables),
+ sizeof(ra::mouse_modifier),
&input_buffer,
&input_size
);
@@ -175,7 +175,7 @@ Return Value:
return;
}
- global.vars = *reinterpret_cast<ra::variables*>(input_buffer);
+ global.modifier = *reinterpret_cast<ra::mouse_modifier*>(input_buffer);
WdfRequestComplete(Request, STATUS_SUCCESS);
}
diff --git a/grapher/Form1.cs b/grapher/Form1.cs
index 1915b01..47ef1d9 100644
--- a/grapher/Form1.cs
+++ b/grapher/Form1.cs
@@ -7,22 +7,89 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
+using System.Runtime.InteropServices;
namespace grapher
{
+ public enum accel_mode
+ {
+ linear=1, classic, natural, logarithmic, sigmoid, power, noaccel
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public struct vec2d
+ {
+ public double x;
+ public double y;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public struct accel_args
+ {
+ public double offset;
+ public double accel;
+ public double limit;
+ public double exponent;
+ public double midpoint;
+ public double power_scale;
+ public vec2d weight;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public struct accel_fn_args
+ {
+ public accel_args acc_args;
+ public int accel_mode;
+ public double time_min;
+ public vec2d cap;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ public struct modifier_args
+ {
+ public double degrees;
+ public vec2d sens;
+ public accel_fn_args acc_fn_args;
+ }
+
public partial class RawAcceleration : Form
{
public RawAcceleration()
{
InitializeComponent();
- var managedAccel = new ManagedAccel(6, 0, 1, 0.025, 0);
+
+ modifier_args args;
+
+ args.degrees = 0;
+ args.sens.x = 1;
+ args.sens.y = 1;
+ args.acc_fn_args.acc_args.offset = 0;
+ args.acc_fn_args.acc_args.accel = 0.01;
+ args.acc_fn_args.acc_args.limit = 2;
+ args.acc_fn_args.acc_args.exponent = 1;
+ args.acc_fn_args.acc_args.midpoint = 0;
+ args.acc_fn_args.acc_args.power_scale = 1;
+ args.acc_fn_args.acc_args.weight.x = 1;
+ args.acc_fn_args.acc_args.weight.y = 1;
+ args.acc_fn_args.accel_mode = (int)accel_mode.natural;
+ args.acc_fn_args.time_min = 0.4;
+ args.acc_fn_args.cap.x = 0;
+ args.acc_fn_args.cap.y = 0;
+
+ IntPtr args_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(args));
+ Marshal.StructureToPtr(args, args_ptr, false);
+
+ var managedAccel = new ManagedAccel(args_ptr);
+
+ Marshal.FreeHGlobal(args_ptr);
+
var orderedPoints = new SortedDictionary<double, double>();
for (int i = 0; i < 100; i++)
{
for (int j = 0; j <= i; j++)
{
- var output = managedAccel.Accelerate(i, j, 1, 6);
+ var output = managedAccel.Accelerate(i, j, 1);
var inMagnitude = Magnitude(i,j);
var outMagnitude = Magnitude(output.Item1, output.Item2);
diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp
index df3f796..26d05ec 100644
--- a/wrapper/wrapper.cpp
+++ b/wrapper/wrapper.cpp
@@ -5,10 +5,13 @@
using namespace rawaccel;
using namespace System;
-Tuple<double, double>^ ManagedAccel::Accelerate(int x, int y, double time, double mode)
+Tuple<double, double>^ ManagedAccel::Accelerate(int x, int y, double time)
{
- vec2d input_vec2d = {x, y};
- vec2d output = (*accel_instance)(input_vec2d, (accel_function::milliseconds)time, (rawaccel::mode)mode);
+ vec2d input_vec2d = {
+ (double)x,
+ (double)y
+ };
+ vec2d output = (*modifier_instance).modify_with_accel(input_vec2d, (milliseconds)time);
return gcnew Tuple<double, double>(output.x, output.y);
} \ No newline at end of file
diff --git a/wrapper/wrapper.hpp b/wrapper/wrapper.hpp
index 24bcadb..42f5865 100644
--- a/wrapper/wrapper.hpp
+++ b/wrapper/wrapper.hpp
@@ -1,52 +1,50 @@
#pragma once
#include "..\common\rawaccel.hpp";
-#include "..\common\rawaccel-userspace.hpp";
+#include "..\common\accel-error.hpp";
#include <iostream>
using namespace rawaccel;
using namespace System;
+
+public value struct ArgsWrapper {
+ int a;
+};
+
public ref class ManagedAccel
{
protected:
- accel_function* accel_instance;
+ mouse_modifier* modifier_instance;
public:
- ManagedAccel(accel_function* accel)
- : accel_instance(accel)
+ ManagedAccel(mouse_modifier* accel)
+ : modifier_instance(accel)
{
}
- ManagedAccel(double mode, double offset, double accel, double lim_exp, double midpoint)
+ ManagedAccel(System::IntPtr args)
{
- accel_function::args_t args{};
- args.accel = accel;
- args.lim_exp = lim_exp;
- args.midpoint = midpoint;
- args.accel_mode = (rawaccel::mode)mode;
- args.offset = offset;
-
- accel_instance = new accel_function(args);
+ modifier_instance = new mouse_modifier(*reinterpret_cast<modifier_args*>(args.ToPointer()));
}
virtual ~ManagedAccel()
{
- if (accel_instance != nullptr)
+ if (modifier_instance!= nullptr)
{
- delete accel_instance;
+ delete modifier_instance;
}
}
!ManagedAccel()
{
- if (accel_instance != nullptr)
+ if (modifier_instance!= nullptr)
{
- delete accel_instance;
+ delete modifier_instance;
}
}
- accel_function* GetInstance()
+ mouse_modifier* GetInstance()
{
- return accel_instance;
+ return modifier_instance;
}
- Tuple<double, double>^ Accelerate(int x, int y, double time, double mode);
+ Tuple<double, double>^ Accelerate(int x, int y, double time);
}; \ No newline at end of file