mirror of
https://github.com/RawAccelOfficial/rawaccel.git
synced 2025-05-11 10:26:58 +02:00
add independent xy accel to driver
other changes: modifier_args type name is now settings, which is now the type passed in driver ioctl remove most settings/args verification from driver, plan to let gui handle most of it add another accel arg, rate, which is used to set the 'accel' parameter of types which call exp (nat/sig), might want to cap it add (update) serializable DriverSettings (ModifierArgs) class to gui and static methods for interop remove properties from ManagedAccel, its now just a black box for accessing modifier methods add exception handling in wrapper_io to throw proper managed types change SettingsManager::Startup to make a new settings file if an error occurs during deserialization change structure of accel types; how offset and weight are applied now depend on additivity of types remove tagged_union and add a handrolled variant/visit impl AccelGui::UpdateActiveValueLabels currently broken for caps and a few other args remove gui default layout and initial natural accel setup cli not updated
This commit is contained in:
parent
313ab92531
commit
9010cc593a
42 changed files with 626 additions and 993 deletions
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
struct natural_impl {
|
||||
double rate;
|
||||
double limit;
|
||||
|
||||
accel_natural(const accel_args& args) : accel_base(args) {
|
||||
verify(args);
|
||||
|
||||
limit = args.limit - 1;
|
||||
speed_coeff /= 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>;
|
||||
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
struct sigmoidgain_impl {
|
||||
double rate;
|
||||
double limit;
|
||||
double additive_constant;
|
||||
double integration_constant;
|
||||
|
||||
accel_sigmoidgain(const accel_args& args) : accel_base(args) {
|
||||
verify(args);
|
||||
|
||||
limit = args.limit - 1;
|
||||
midpoint = args.midpoint;
|
||||
additive_constant = exp(speed_coeff*midpoint);
|
||||
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>;
|
||||
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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(const 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,8 +63,8 @@ namespace rawaccel {
|
|||
BOOL success = DeviceIoControl(
|
||||
ra_handle,
|
||||
RA_WRITE,
|
||||
const_cast<mouse_modifier*>(&mod), // input buffer
|
||||
sizeof(mouse_modifier), // input buffer size
|
||||
const_cast<settings*>(&args), // input buffer
|
||||
sizeof(settings), // input buffer size
|
||||
NULL, // output buffer
|
||||
0, // output buffer size
|
||||
&dummy, // bytes returned
|
||||
|
|
21
common/rawaccel-settings.h
Normal file
21
common/rawaccel-settings.h
Normal file
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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>;
|
||||
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);
|
||||
}
|
||||
|
||||
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 };
|
||||
};
|
||||
struct accelerator {
|
||||
accel_variant accel;
|
||||
velocity_gain_cap gain_cap;
|
||||
accel_scale_clamp clamp;
|
||||
|
||||
/// <summary> Struct for holding acceleration application details. </summary>
|
||||
struct accel_function {
|
||||
accelerator(const accel_args& args, accel_mode mode) :
|
||||
accel(args, mode), gain_cap(args.gain_cap, accel), clamp(args.scale_cap)
|
||||
{}
|
||||
|
||||
/*
|
||||
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;
|
||||
|
||||
/// <summary> The acceleration implementation (i.e. curve) </summary>
|
||||
accel_impl_t accel;
|
||||
|
||||
/// <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);
|
||||
inline double apply(double speed) const {
|
||||
if (gain_cap.should_apply(speed)) {
|
||||
return clamp(gain_cap.apply(speed));
|
||||
}
|
||||
else return clamp(accel.apply(speed));
|
||||
}
|
||||
|
||||
/// <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 };
|
||||
}
|
||||
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)
|
||||
};
|
||||
}
|
||||
|
||||
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 (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 (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);
|
||||
if ((combine_magnitudes && args.modes.x == accel_mode::noaccel) ||
|
||||
(args.modes.x == accel_mode::noaccel &&
|
||||
args.modes.y == accel_mode::noaccel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
input.x *= sensitivity.x;
|
||||
input.y *= sensitivity.y;
|
||||
|
||||
return input;
|
||||
accels.x = accelerator(args.argsv.x, args.modes.x);
|
||||
accels.y = accelerator(args.argsv.y, args.modes.y);
|
||||
apply_accel = true;
|
||||
}
|
||||
|
||||
/// <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);
|
||||
void modify(vec2d& movement, milliseconds time) {
|
||||
apply_rotation(movement);
|
||||
apply_acceleration(movement, [=] { return time; });
|
||||
apply_sensitivity(movement);
|
||||
}
|
||||
|
||||
inline void apply_rotation(vec2d& movement) {
|
||||
if (apply_rotate) movement = rotate.apply(movement);
|
||||
}
|
||||
|
||||
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
|
||||
} // rawaccel
|
||||
|
|
|
@ -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...>;
|
|
@ -14,9 +14,10 @@ namespace ra = rawaccel;
|
|||
using milliseconds = double;
|
||||
|
||||
struct {
|
||||
counter_t last_write = 0;
|
||||
ra::settings args;
|
||||
milliseconds tick_interval = 0; // set in DriverEntry
|
||||
ra::mouse_modifier modifier;
|
||||
counter_t last_write = 0;
|
||||
} global;
|
||||
|
||||
VOID
|
||||
|
@ -52,16 +53,12 @@ Arguments:
|
|||
|
||||
if (!(InputDataStart->Flags & MOUSE_MOVE_ABSOLUTE)) {
|
||||
auto num_packets = InputDataEnd - InputDataStart;
|
||||
|
||||
|
||||
// if IO is backed up to the point where we get more than 1 packet here
|
||||
// then applying accel is pointless as we can't get an accurate timing
|
||||
|
||||
bool local_apply_accel = num_packets == 1;
|
||||
if (num_packets != 1) {
|
||||
DebugPrint(("RA received %d packets\n", num_packets));
|
||||
}
|
||||
|
||||
vec2d local_carry = devExt->carry;
|
||||
bool enable_accel = num_packets == 1;
|
||||
|
||||
vec2d carry = devExt->carry;
|
||||
|
||||
auto it = InputDataStart;
|
||||
do {
|
||||
|
@ -70,39 +67,37 @@ Arguments:
|
|||
static_cast<double>(it->LastY)
|
||||
};
|
||||
|
||||
if (global.modifier.apply_accel && local_apply_accel) {
|
||||
counter_t now = KeQueryPerformanceCounter(NULL).QuadPart;
|
||||
counter_t ticks = now - devExt->counter;
|
||||
devExt->counter = now;
|
||||
global.modifier.apply_rotation(input);
|
||||
|
||||
milliseconds time = ticks * global.tick_interval;
|
||||
if (time < global.modifier.accel_fn.time_min) {
|
||||
DebugPrint(("RA time < min with %d ticks\n", ticks));
|
||||
}
|
||||
if (enable_accel) {
|
||||
auto time_supplier = [=] {
|
||||
counter_t now = KeQueryPerformanceCounter(NULL).QuadPart;
|
||||
counter_t ticks = now - devExt->counter;
|
||||
devExt->counter = now;
|
||||
milliseconds time = ticks * global.tick_interval;
|
||||
return clampsd(time, global.args.time_min, 100);
|
||||
};
|
||||
|
||||
input = global.modifier.modify_with_accel(input, time);
|
||||
}
|
||||
else
|
||||
{
|
||||
input = global.modifier.modify_without_accel(input);
|
||||
global.modifier.apply_acceleration(input, time_supplier);
|
||||
}
|
||||
|
||||
double result_x = input.x + local_carry.x;
|
||||
double result_y = input.y + local_carry.y;
|
||||
global.modifier.apply_sensitivity(input);
|
||||
|
||||
LONG out_x = static_cast<LONG>(result_x);
|
||||
LONG out_y = static_cast<LONG>(result_y);
|
||||
double carried_result_x = input.x + carry.x;
|
||||
double carried_result_y = input.y + carry.y;
|
||||
|
||||
local_carry.x = result_x - out_x;
|
||||
local_carry.y = result_y - out_y;
|
||||
LONG out_x = static_cast<LONG>(carried_result_x);
|
||||
LONG out_y = static_cast<LONG>(carried_result_y);
|
||||
|
||||
carry.x = carried_result_x - out_x;
|
||||
carry.y = carried_result_y - out_y;
|
||||
|
||||
it->LastX = out_x;
|
||||
it->LastY = out_y;
|
||||
|
||||
++it;
|
||||
} while (it < InputDataEnd);
|
||||
} while (++it != InputDataEnd);
|
||||
|
||||
devExt->carry = local_carry;
|
||||
devExt->carry = carry;
|
||||
}
|
||||
|
||||
(*(PSERVICE_CALLBACK_ROUTINE)devExt->UpperConnectData.ClassService)(
|
||||
|
@ -154,7 +149,7 @@ Return Value:
|
|||
|
||||
DebugPrint(("Ioctl received into filter control object.\n"));
|
||||
|
||||
if (InputBufferLength == sizeof(ra::mouse_modifier)) {
|
||||
if (InputBufferLength == sizeof(ra::settings)) {
|
||||
constexpr milliseconds WRITE_COOLDOWN_TIME = 1000;
|
||||
|
||||
counter_t now = KeQueryPerformanceCounter(NULL).QuadPart;
|
||||
|
@ -170,7 +165,7 @@ Return Value:
|
|||
|
||||
status = WdfRequestRetrieveInputBuffer(
|
||||
Request,
|
||||
sizeof(ra::mouse_modifier),
|
||||
sizeof(ra::settings),
|
||||
&buffer,
|
||||
&size
|
||||
);
|
||||
|
@ -182,15 +177,16 @@ Return Value:
|
|||
return;
|
||||
}
|
||||
|
||||
global.modifier = *reinterpret_cast<ra::mouse_modifier*>(buffer);
|
||||
global.args = *reinterpret_cast<ra::settings*>(buffer);
|
||||
global.modifier = { global.args };
|
||||
global.last_write = now;
|
||||
|
||||
WdfRequestComplete(Request, STATUS_SUCCESS);
|
||||
}
|
||||
else if (OutputBufferLength == sizeof(ra::mouse_modifier)) {
|
||||
else if (OutputBufferLength == sizeof(ra::settings)) {
|
||||
status = WdfRequestRetrieveOutputBuffer(
|
||||
Request,
|
||||
sizeof(ra::mouse_modifier),
|
||||
sizeof(ra::settings),
|
||||
&buffer,
|
||||
&size
|
||||
);
|
||||
|
@ -202,7 +198,7 @@ Return Value:
|
|||
return;
|
||||
}
|
||||
|
||||
*reinterpret_cast<ra::mouse_modifier*>(buffer) = global.modifier;
|
||||
*reinterpret_cast<ra::settings*>(buffer) = global.args;
|
||||
|
||||
WdfRequestComplete(Request, STATUS_SUCCESS);
|
||||
}
|
||||
|
|
|
@ -15,48 +15,6 @@ using grapher.Models.Serialized;
|
|||
|
||||
namespace grapher
|
||||
{
|
||||
public enum accel_mode
|
||||
{
|
||||
linear=1, classic, natural, logarithmic, sigmoid, power, naturalgain, sigmoidgain, 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 double gain_cap;
|
||||
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
|
||||
{
|
||||
|
||||
|
@ -66,32 +24,17 @@ namespace grapher
|
|||
public RawAcceleration()
|
||||
{
|
||||
InitializeComponent();
|
||||
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.acc_args.gain_cap = 0;
|
||||
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 managedAcceleration = new ManagedAccel(args_ptr);
|
||||
|
||||
Marshal.FreeHGlobal(args_ptr);
|
||||
ManagedAccel activeAccel = null;
|
||||
|
||||
try
|
||||
{
|
||||
activeAccel = ManagedAccel.GetActiveAccel();
|
||||
}
|
||||
catch (DriverNotInstalledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
var accelCharts = new AccelCharts(
|
||||
this,
|
||||
|
@ -205,7 +148,7 @@ namespace grapher
|
|||
new Field(PollRateTextBox.TextBox, this, AccelCalculator.DefaultPollRate));
|
||||
|
||||
var settings = new SettingsManager(
|
||||
managedAcceleration,
|
||||
activeAccel,
|
||||
accelCalculator.DPI,
|
||||
accelCalculator.PollRate,
|
||||
AutoWriteMenuItem);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using grapher.Models.Serialized;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
@ -12,7 +13,7 @@ namespace grapher.Layouts
|
|||
: base()
|
||||
{
|
||||
Name = "Classic";
|
||||
Index = 2;
|
||||
Index = (int)AccelMode.classic;
|
||||
ShowOptions = new bool[] { true, true, true, false };
|
||||
OptionNames = new string[] { Offset, Acceleration, Exponent, string.Empty };
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
using System;
|
||||
using grapher.Models.Serialized;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
|
||||
namespace grapher.Layouts
|
||||
{
|
||||
public class DefaultLayout : LayoutBase
|
||||
|
@ -13,7 +15,7 @@ namespace grapher.Layouts
|
|||
: base()
|
||||
{
|
||||
Name = "Default";
|
||||
Index = 0;
|
||||
Index = (int)AccelMode.noaccel;
|
||||
ShowOptions = new bool[] { true, true, true, true };
|
||||
OptionNames = new string[] { Offset, Acceleration, $"{Limit}\\{Exponent}", Midpoint };
|
||||
ButtonEnabled = false;
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace grapher.Layouts
|
|||
|
||||
/// <summary>
|
||||
/// Gets or sets mapping from acceleration type to identifying integer.
|
||||
/// Must match order in tagged_union in rawaccel.hpp (which is 1-indexed, meaning 0 is off.)
|
||||
/// Must match accel_mode defined in rawaccel-settings.h
|
||||
/// </summary>
|
||||
public int Index { get; internal set; }
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using grapher.Models.Serialized;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
@ -12,7 +13,7 @@ namespace grapher.Layouts
|
|||
: base()
|
||||
{
|
||||
Name = "Linear";
|
||||
Index = 1;
|
||||
Index = (int)AccelMode.linear;
|
||||
ShowOptions = new bool[] { true, true, false, false };
|
||||
OptionNames = new string[] { Offset, Acceleration, string.Empty, string.Empty };
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using grapher.Models.Serialized;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
@ -12,7 +13,7 @@ namespace grapher.Layouts
|
|||
: base()
|
||||
{
|
||||
Name = "Logarithmic";
|
||||
Index = 4;
|
||||
Index = (int)AccelMode.logarithmic;
|
||||
ShowOptions = new bool[] { true, true, false, false };
|
||||
OptionNames = new string[] { Offset, Acceleration, string.Empty, string.Empty };
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using grapher.Models.Serialized;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
@ -12,7 +13,7 @@ namespace grapher.Layouts
|
|||
: base()
|
||||
{
|
||||
Name = "NaturalGain";
|
||||
Index = 7;
|
||||
Index = (int)AccelMode.naturalgain;
|
||||
ShowOptions = new bool[] { true, true, true, false };
|
||||
OptionNames = new string[] { Offset, Acceleration, Limit, string.Empty };
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using grapher.Models.Serialized;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
@ -12,7 +13,7 @@ namespace grapher.Layouts
|
|||
: base()
|
||||
{
|
||||
Name = "Natural";
|
||||
Index = 3;
|
||||
Index = (int)AccelMode.natural;
|
||||
ShowOptions = new bool[] { true, true, true, false };
|
||||
OptionNames = new string[] { Offset, Acceleration, Limit, string.Empty };
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using grapher.Models.Serialized;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
@ -12,7 +13,7 @@ namespace grapher.Layouts
|
|||
: base()
|
||||
{
|
||||
Name = "Off";
|
||||
Index = 9;
|
||||
Index = (int)AccelMode.noaccel;
|
||||
ShowOptions = new bool[] { false, false, false, false };
|
||||
OptionNames = new string[] { string.Empty, string.Empty, string.Empty, string.Empty };
|
||||
ShowOptionsXY = new bool[] { false, false };
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using grapher.Models.Serialized;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
@ -12,7 +13,7 @@ namespace grapher.Layouts
|
|||
: base()
|
||||
{
|
||||
Name = "Power";
|
||||
Index = 6;
|
||||
Index = (int)AccelMode.power;
|
||||
ShowOptions = new bool[] { true, true, true, false };
|
||||
OptionNames = new string[] { Offset, Scale, Exponent, string.Empty };
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using grapher.Models.Serialized;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
@ -12,7 +13,7 @@ namespace grapher.Layouts
|
|||
: base()
|
||||
{
|
||||
Name = "SigmoidGain";
|
||||
Index = 8;
|
||||
Index = (int)AccelMode.sigmoidgain;
|
||||
ShowOptions = new bool[] { true, true, true, true };
|
||||
OptionNames = new string[] { Offset, Acceleration, Limit, Midpoint };
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using grapher.Models.Serialized;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
@ -12,7 +13,7 @@ namespace grapher.Layouts
|
|||
: base()
|
||||
{
|
||||
Name = "Sigmoid";
|
||||
Index = 5;
|
||||
Index = (int)AccelMode.sigmoid;
|
||||
ShowOptions = new bool[] { true, true, true, true };
|
||||
OptionNames = new string[] { Offset, Acceleration, Limit, Midpoint };
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using grapher.Models.Mouse;
|
||||
using grapher.Models.Serialized;
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
@ -101,41 +102,64 @@ namespace grapher
|
|||
|
||||
public void UpdateActiveSettingsFromFields()
|
||||
{
|
||||
Settings.UpdateActiveSettings(
|
||||
AccelerationOptions.AccelerationIndex,
|
||||
Rotation.Field.Data,
|
||||
Sensitivity.Fields.X,
|
||||
Sensitivity.Fields.Y,
|
||||
Weight.Fields.X,
|
||||
Weight.Fields.Y,
|
||||
Cap.SensitivityCapX,
|
||||
Cap.SensitivityCapY,
|
||||
Offset.Field.Data,
|
||||
Acceleration.Field.Data,
|
||||
LimitOrExponent.Field.Data,
|
||||
Midpoint.Field.Data,
|
||||
Cap.VelocityGainCap);
|
||||
Settings.UpdateActiveSettings(new DriverSettings
|
||||
{
|
||||
rotation = Rotation.Field.Data,
|
||||
sensitivity = new Vec2<double>
|
||||
{
|
||||
x = Sensitivity.Fields.X,
|
||||
y = Sensitivity.Fields.Y
|
||||
},
|
||||
combineMagnitudes = true,
|
||||
modes = new Vec2<AccelMode>
|
||||
{
|
||||
x = (AccelMode)AccelerationOptions.AccelerationIndex
|
||||
},
|
||||
args = new Vec2<AccelArgs>
|
||||
{
|
||||
x = new AccelArgs
|
||||
{
|
||||
offset = Offset.Field.Data,
|
||||
weight = Weight.Fields.X,
|
||||
gainCap = Cap.VelocityGainCap,
|
||||
scaleCap = Cap.SensitivityCapX,
|
||||
accel = Acceleration.Field.Data,
|
||||
rate = Acceleration.Field.Data,
|
||||
powerScale = Acceleration.Field.Data,
|
||||
limit = LimitOrExponent.Field.Data,
|
||||
exponent = LimitOrExponent.Field.Data,
|
||||
powerExponent = LimitOrExponent.Field.Data,
|
||||
midpoint = Midpoint.Field.Data
|
||||
}
|
||||
},
|
||||
minimumTime = .4
|
||||
});
|
||||
UpdateGraph();
|
||||
}
|
||||
|
||||
public void UpdateGraph()
|
||||
{
|
||||
AccelCalculator.Calculate(AccelCharts.AccelData, Settings.ActiveAccel);
|
||||
AccelCalculator.Calculate(
|
||||
AccelCharts.AccelData,
|
||||
Settings.ActiveAccel,
|
||||
Settings.RawAccelSettings.AccelerationSettings);
|
||||
AccelCharts.Bind();
|
||||
UpdateActiveValueLabels();
|
||||
}
|
||||
|
||||
public void UpdateActiveValueLabels()
|
||||
{
|
||||
Sensitivity.SetActiveValues(Settings.ActiveAccel.SensitivityX, Settings.ActiveAccel.SensitivityY);
|
||||
Rotation.SetActiveValue(Settings.ActiveAccel.Rotation);
|
||||
AccelerationOptions.SetActiveValue(Settings.ActiveAccel.Type);
|
||||
Offset.SetActiveValue(Settings.ActiveAccel.Offset);
|
||||
Acceleration.SetActiveValue(Settings.ActiveAccel.Acceleration);
|
||||
Cap.SetActiveValues(Settings.ActiveAccel.GainCap, Settings.ActiveAccel.CapX, Settings.ActiveAccel.CapY, Settings.ActiveAccel.GainCapEnabled);
|
||||
Weight.SetActiveValues(Settings.ActiveAccel.WeightX, Settings.ActiveAccel.WeightY);
|
||||
LimitOrExponent.SetActiveValue(Settings.ActiveAccel.LimitExp);
|
||||
Midpoint.SetActiveValue(Settings.ActiveAccel.Midpoint);
|
||||
var settings = Settings.RawAccelSettings.AccelerationSettings;
|
||||
|
||||
Sensitivity.SetActiveValues(settings.sensitivity.x, settings.sensitivity.y);
|
||||
Rotation.SetActiveValue(settings.rotation);
|
||||
AccelerationOptions.SetActiveValue((int)settings.modes.x);
|
||||
Offset.SetActiveValue(settings.args.x.offset);
|
||||
Weight.SetActiveValues(settings.args.x.weight, settings.args.x.weight);
|
||||
Acceleration.SetActiveValue(settings.args.x.accel); // rate, powerscale
|
||||
LimitOrExponent.SetActiveValue(settings.args.x.limit); //exp, powerexp
|
||||
Midpoint.SetActiveValue(settings.args.x.midpoint);
|
||||
//Cap.SetActiveValues(Settings.ActiveAccel.GainCap, Settings.ActiveAccel.CapX, Settings.ActiveAccel.CapY, Settings.ActiveAccel.GainCapEnabled);
|
||||
}
|
||||
|
||||
private void OnScaleMenuItemClick(object sender, EventArgs e)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using grapher.Models.Serialized;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
@ -46,15 +47,15 @@ namespace grapher.Models.Calculations
|
|||
|
||||
private int Increment { get; set; }
|
||||
|
||||
public void Calculate(AccelData data, ManagedAccel accel)
|
||||
public void Calculate(AccelData data, ManagedAccel accel, DriverSettings settings)
|
||||
{
|
||||
ScaleByMouseSettings();
|
||||
|
||||
data.Clear();
|
||||
|
||||
Calculate(data.Combined, accel, accel.SensitivityX, MagnitudesCombined);
|
||||
Calculate(data.X, accel, accel.SensitivityX, MagnitudesX);
|
||||
Calculate(data.Y, accel, accel.SensitivityY, MagnitudesY);
|
||||
Calculate(data.Combined, accel, settings.sensitivity.x, MagnitudesCombined);
|
||||
Calculate(data.X, accel, settings.sensitivity.x, MagnitudesX);
|
||||
Calculate(data.Y, accel, settings.sensitivity.y, MagnitudesY);
|
||||
}
|
||||
|
||||
public static void Calculate(AccelChartData data, ManagedAccel accel, double starter, ICollection<MagnitudeData> magnitudeData)
|
||||
|
|
|
@ -16,7 +16,6 @@ namespace grapher
|
|||
|
||||
public static readonly Dictionary<string, LayoutBase> AccelerationTypes = new List<LayoutBase>
|
||||
{
|
||||
new DefaultLayout(),
|
||||
new LinearLayout(),
|
||||
new ClassicLayout(),
|
||||
new NaturalLayout(),
|
||||
|
@ -37,7 +36,7 @@ namespace grapher
|
|||
{
|
||||
AccelDropdown = accelDropdown;
|
||||
AccelDropdown.Items.Clear();
|
||||
AccelDropdown.Items.AddRange(AccelerationTypes.Keys.Skip(1).ToArray());
|
||||
AccelDropdown.Items.AddRange(AccelerationTypes.Keys.ToArray());
|
||||
AccelDropdown.SelectedIndexChanged += new System.EventHandler(OnIndexChanged);
|
||||
|
||||
if (options.Length > PossibleOptionsCount)
|
||||
|
@ -55,7 +54,7 @@ namespace grapher
|
|||
WriteButton = writeButton;
|
||||
ActiveValueLabel = activeValueLabel;
|
||||
|
||||
Layout("Default");
|
||||
Layout("Off");
|
||||
}
|
||||
|
||||
public Button WriteButton { get; }
|
||||
|
|
87
grapher/Models/Serialized/DriverSettings.cs
Normal file
87
grapher/Models/Serialized/DriverSettings.cs
Normal file
|
@ -0,0 +1,87 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace grapher.Models.Serialized
|
||||
{
|
||||
public enum AccelMode
|
||||
{
|
||||
linear, classic, natural, logarithmic, sigmoid, naturalgain, sigmoidgain, power, noaccel
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct AccelArgs
|
||||
{
|
||||
public double offset;
|
||||
public double accel;
|
||||
public double limit;
|
||||
public double exponent;
|
||||
public double midpoint;
|
||||
public double powerScale;
|
||||
public double powerExponent;
|
||||
public double weight;
|
||||
public double rate;
|
||||
public double scaleCap;
|
||||
public double gainCap;
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Vec2 <T>
|
||||
{
|
||||
public T x;
|
||||
public T y;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[Serializable]
|
||||
public class DriverSettings
|
||||
{
|
||||
private static readonly IntPtr UnmanagedSettingsHandle =
|
||||
Marshal.AllocHGlobal(Marshal.SizeOf<DriverSettings>());
|
||||
|
||||
public double rotation;
|
||||
public bool combineMagnitudes;
|
||||
public Vec2<AccelMode> modes;
|
||||
public Vec2<AccelArgs> args;
|
||||
public Vec2<double> sensitivity;
|
||||
public double minimumTime;
|
||||
|
||||
public static DriverSettings GetActive()
|
||||
{
|
||||
DriverInterop.GetActiveSettings(UnmanagedSettingsHandle);
|
||||
return Marshal.PtrToStructure<DriverSettings>(UnmanagedSettingsHandle);
|
||||
}
|
||||
|
||||
public static void SetActive(DriverSettings settings)
|
||||
{
|
||||
Marshal.StructureToPtr(settings, UnmanagedSettingsHandle, false);
|
||||
DriverInterop.SetActiveSettings(UnmanagedSettingsHandle);
|
||||
}
|
||||
|
||||
public void SendToDriver()
|
||||
{
|
||||
SetActive(this);
|
||||
}
|
||||
|
||||
public void SendToDriverAndUpdate(ManagedAccel accel)
|
||||
{
|
||||
SendToDriver();
|
||||
accel.UpdateFromSettings(UnmanagedSettingsHandle);
|
||||
}
|
||||
|
||||
public bool verify()
|
||||
{
|
||||
/*
|
||||
if (args.accel < 0 || args.rate < 0)
|
||||
bad_arg("accel can not be negative, use a negative weight to compensate");
|
||||
if (args.rate > 1) bad_arg("rate can not be greater than 1");
|
||||
if (args.exponent <= 1) bad_arg("exponent must be greater than 1");
|
||||
if (args.limit <= 1) bad_arg("limit must be greater than 1");
|
||||
if (args.power_scale <= 0) bad_arg("scale must be positive");
|
||||
if (args.power_exp <= 0) bad_arg("exponent must be positive");
|
||||
if (args.midpoint < 0) bad_arg("midpoint must not be negative");
|
||||
if (args.time_min <= 0) bad_arg("min time must be positive");
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace grapher.Models.Serialized
|
||||
{
|
||||
public enum accel_mode
|
||||
{
|
||||
linear=1, classic, natural, logarithmic, sigmoid, power, naturalgain, sigmoidgain, noaccel
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
[Serializable]
|
||||
public struct vec2d
|
||||
{
|
||||
public double x;
|
||||
public double y;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
[Serializable]
|
||||
public struct accel_args
|
||||
{
|
||||
public double offset;
|
||||
public double accel;
|
||||
public double limit;
|
||||
public double exponent;
|
||||
public double midpoint;
|
||||
public double power_scale;
|
||||
public double gain_cap;
|
||||
public vec2d weight;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
[Serializable]
|
||||
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)]
|
||||
[Serializable]
|
||||
public struct modifier_args
|
||||
{
|
||||
public double degrees;
|
||||
public vec2d sens;
|
||||
public accel_fn_args acc_fn_args;
|
||||
|
||||
public modifier_args(ManagedAccel managedAccel)
|
||||
{
|
||||
degrees = managedAccel.Rotation;
|
||||
sens.x = managedAccel.SensitivityX;
|
||||
sens.y = managedAccel.SensitivityY;
|
||||
acc_fn_args.accel_mode = managedAccel.Type;
|
||||
acc_fn_args.time_min = managedAccel.MinimumTime;
|
||||
acc_fn_args.cap.x = managedAccel.CapX;
|
||||
acc_fn_args.cap.y = managedAccel.CapY;
|
||||
acc_fn_args.acc_args.accel = managedAccel.Acceleration;
|
||||
acc_fn_args.acc_args.exponent = managedAccel.LimitExp;
|
||||
acc_fn_args.acc_args.gain_cap = managedAccel.GainCap;
|
||||
acc_fn_args.acc_args.limit = managedAccel.LimitExp;
|
||||
acc_fn_args.acc_args.midpoint = managedAccel.Midpoint;
|
||||
acc_fn_args.acc_args.offset = managedAccel.Offset;
|
||||
acc_fn_args.acc_args.power_scale = managedAccel.PowerScale;
|
||||
acc_fn_args.acc_args.weight.x = managedAccel.WeightX;
|
||||
acc_fn_args.acc_args.weight.y = managedAccel.WeightY;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,17 +24,16 @@ namespace grapher.Models.Serialized
|
|||
public RawAccelSettings() { }
|
||||
|
||||
public RawAccelSettings(
|
||||
ManagedAccel managedAccel,
|
||||
DriverSettings accelSettings,
|
||||
GUISettings guiSettings)
|
||||
{
|
||||
AccelerationSettings = new modifier_args(managedAccel);
|
||||
AccelerationSettings = accelSettings;
|
||||
GUISettings = guiSettings;
|
||||
}
|
||||
|
||||
|
||||
public GUISettings GUISettings { get; set; }
|
||||
|
||||
public modifier_args AccelerationSettings { get; set; }
|
||||
public DriverSettings AccelerationSettings { get; set; }
|
||||
|
||||
public static RawAccelSettings Load()
|
||||
{
|
||||
|
@ -42,23 +41,19 @@ namespace grapher.Models.Serialized
|
|||
}
|
||||
|
||||
public static RawAccelSettings Load(string file)
|
||||
{
|
||||
if (!Exists(file))
|
||||
{
|
||||
throw new Exception($"Settings file does not exist at {file}");
|
||||
}
|
||||
|
||||
RawAccelSettings deserializedSettings;
|
||||
{
|
||||
try
|
||||
{
|
||||
deserializedSettings = JsonConvert.DeserializeObject<RawAccelSettings>(File.ReadAllText(file), SerializerSettings);
|
||||
return JsonConvert.DeserializeObject<RawAccelSettings>(File.ReadAllText(file), SerializerSettings);
|
||||
}
|
||||
catch(Exception e)
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
throw new Exception($"Settings file at {file} does not contain valid Raw Accel Settings.", e);
|
||||
throw new FileNotFoundException($"Settings file does not exist at {file}", e);
|
||||
}
|
||||
catch (JsonSerializationException e)
|
||||
{
|
||||
throw new JsonSerializationException($"Settings file at {file} does not contain valid Raw Accel Settings.", e);
|
||||
}
|
||||
|
||||
return deserializedSettings;
|
||||
}
|
||||
|
||||
public static bool Exists()
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace grapher.Models.Serialized
|
||||
|
@ -32,63 +28,38 @@ namespace grapher.Models.Serialized
|
|||
|
||||
private ToolStripMenuItem AutoWriteMenuItem { get; set; }
|
||||
|
||||
public void UpdateActiveSettings(
|
||||
int mode,
|
||||
double degrees,
|
||||
double sensitivityX,
|
||||
double sensitivityY,
|
||||
double weightX,
|
||||
double weightY,
|
||||
double capX,
|
||||
double capY,
|
||||
double offset,
|
||||
double accel,
|
||||
double limitOrExp,
|
||||
double midpoint,
|
||||
double gainCap)
|
||||
public void UpdateActiveSettings(DriverSettings settings)
|
||||
{
|
||||
ActiveAccel.UpdateAccel(
|
||||
mode,
|
||||
degrees,
|
||||
sensitivityX,
|
||||
sensitivityY,
|
||||
weightX,
|
||||
weightY,
|
||||
capX,
|
||||
capY,
|
||||
offset,
|
||||
accel,
|
||||
limitOrExp,
|
||||
midpoint,
|
||||
gainCap);
|
||||
try
|
||||
{
|
||||
settings.SendToDriverAndUpdate(ActiveAccel);
|
||||
|
||||
RawAccelSettings.AccelerationSettings = new modifier_args(ActiveAccel);
|
||||
RawAccelSettings.GUISettings = new GUISettings
|
||||
RawAccelSettings.AccelerationSettings = settings;
|
||||
RawAccelSettings.GUISettings = new GUISettings
|
||||
{
|
||||
AutoWriteToDriverOnStartup = AutoWriteMenuItem.Checked,
|
||||
DPI = (int)DpiField.Data,
|
||||
PollRate = (int)PollRateField.Data
|
||||
};
|
||||
|
||||
RawAccelSettings.Save();
|
||||
RawAccelSettings.Save();
|
||||
}
|
||||
catch (DriverWriteCDException)
|
||||
{
|
||||
Console.WriteLine("write on cooldown");
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateActiveAccelFromFileSettings()
|
||||
public void UpdateActiveAccelFromFileSettings(DriverSettings settings)
|
||||
{
|
||||
ActiveAccel.UpdateAccel(
|
||||
RawAccelSettings.AccelerationSettings.acc_fn_args.accel_mode,
|
||||
RawAccelSettings.AccelerationSettings.degrees,
|
||||
RawAccelSettings.AccelerationSettings.sens.x,
|
||||
RawAccelSettings.AccelerationSettings.sens.y,
|
||||
RawAccelSettings.AccelerationSettings.acc_fn_args.acc_args.weight.x,
|
||||
RawAccelSettings.AccelerationSettings.acc_fn_args.acc_args.weight.y,
|
||||
RawAccelSettings.AccelerationSettings.acc_fn_args.cap.x,
|
||||
RawAccelSettings.AccelerationSettings.acc_fn_args.cap.y,
|
||||
RawAccelSettings.AccelerationSettings.acc_fn_args.acc_args.offset,
|
||||
RawAccelSettings.AccelerationSettings.acc_fn_args.acc_args.accel,
|
||||
RawAccelSettings.AccelerationSettings.acc_fn_args.acc_args.exponent,
|
||||
RawAccelSettings.AccelerationSettings.acc_fn_args.acc_args.midpoint,
|
||||
RawAccelSettings.AccelerationSettings.acc_fn_args.acc_args.gain_cap);
|
||||
try
|
||||
{
|
||||
settings.SendToDriverAndUpdate(ActiveAccel);
|
||||
}
|
||||
catch (DriverWriteCDException)
|
||||
{
|
||||
Console.WriteLine("write on cd during file init");
|
||||
}
|
||||
DpiField.SetToEntered(RawAccelSettings.GUISettings.DPI);
|
||||
PollRateField.SetToEntered(RawAccelSettings.GUISettings.PollRate);
|
||||
AutoWriteMenuItem.Checked = RawAccelSettings.GUISettings.AutoWriteToDriverOnStartup;
|
||||
|
@ -96,28 +67,32 @@ namespace grapher.Models.Serialized
|
|||
|
||||
public void Startup()
|
||||
{
|
||||
ActiveAccel.ReadFromDriver();
|
||||
|
||||
if(RawAccelSettings.Exists())
|
||||
if (RawAccelSettings.Exists())
|
||||
{
|
||||
RawAccelSettings = RawAccelSettings.Load();
|
||||
if (RawAccelSettings.GUISettings.AutoWriteToDriverOnStartup)
|
||||
try
|
||||
{
|
||||
UpdateActiveAccelFromFileSettings();
|
||||
RawAccelSettings = RawAccelSettings.Load();
|
||||
if (RawAccelSettings.GUISettings.AutoWriteToDriverOnStartup)
|
||||
{
|
||||
UpdateActiveAccelFromFileSettings(RawAccelSettings.AccelerationSettings);
|
||||
}
|
||||
return;
|
||||
}
|
||||
catch (JsonSerializationException e)
|
||||
{
|
||||
Console.WriteLine($"bad settings: {e}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RawAccelSettings = new RawAccelSettings(
|
||||
ActiveAccel,
|
||||
new GUISettings
|
||||
{
|
||||
AutoWriteToDriverOnStartup = AutoWriteMenuItem.Checked,
|
||||
DPI = (int)DpiField.Data,
|
||||
PollRate = (int)PollRateField.Data
|
||||
});
|
||||
RawAccelSettings.Save();
|
||||
}
|
||||
|
||||
RawAccelSettings = new RawAccelSettings(
|
||||
DriverSettings.GetActive(),
|
||||
new GUISettings
|
||||
{
|
||||
AutoWriteToDriverOnStartup = AutoWriteMenuItem.Checked,
|
||||
DPI = (int)DpiField.Data,
|
||||
PollRate = (int)PollRateField.Data
|
||||
});
|
||||
RawAccelSettings.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
<Compile Include="Models\Options\Option.cs" />
|
||||
<Compile Include="Models\Options\OptionXY.cs" />
|
||||
<Compile Include="Models\Serialized\GUISettings.cs" />
|
||||
<Compile Include="Models\Serialized\ModifierArgs.cs" />
|
||||
<Compile Include="Models\Serialized\DriverSettings.cs" />
|
||||
<Compile Include="Models\Serialized\RawAccelSettings.cs" />
|
||||
<Compile Include="Models\Serialized\SettingsManager.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
|
|
|
@ -1,80 +1,62 @@
|
|||
#pragma once
|
||||
|
||||
#include "wrapper.hpp"
|
||||
#include <rawaccel.hpp>
|
||||
|
||||
void replace(mouse_modifier* mod_ptr, const modifier_args& args) {
|
||||
*mod_ptr = mouse_modifier(args);
|
||||
}
|
||||
#include "wrapper_io.hpp"
|
||||
|
||||
Tuple<double, double>^ ManagedAccel::Accelerate(int x, int y, double time)
|
||||
using namespace System;
|
||||
|
||||
public ref struct DriverInterop
|
||||
{
|
||||
vec2d input_vec2d = {
|
||||
(double)x,
|
||||
(double)y
|
||||
};
|
||||
vec2d output = modifier_instance->modify_with_accel(input_vec2d, time);
|
||||
static void GetActiveSettings(IntPtr argsOut)
|
||||
{
|
||||
wrapper_io::readFromDriver(*reinterpret_cast<settings*>(argsOut.ToPointer()));
|
||||
}
|
||||
|
||||
return gcnew Tuple<double, double>(output.x, output.y);
|
||||
}
|
||||
static void SetActiveSettings(IntPtr argsIn)
|
||||
{
|
||||
wrapper_io::writeToDriver(*reinterpret_cast<settings*>(argsIn.ToPointer()));
|
||||
}
|
||||
};
|
||||
|
||||
void ManagedAccel::UpdateAccel(
|
||||
int mode,
|
||||
double rotation,
|
||||
double sensitivityX,
|
||||
double sensitivityY,
|
||||
double weightX,
|
||||
double weightY,
|
||||
double capX,
|
||||
double capY,
|
||||
double offset,
|
||||
double accel,
|
||||
double lim_exp,
|
||||
double midpoint,
|
||||
double gain_cap)
|
||||
public ref class ManagedAccel
|
||||
{
|
||||
modifier_args args{};
|
||||
args.acc_fn_args.accel_mode = mode;
|
||||
args.degrees = rotation;
|
||||
args.sens.x = sensitivityX;
|
||||
args.sens.y = sensitivityY;
|
||||
args.acc_fn_args.acc_args.weight.x = weightX;
|
||||
args.acc_fn_args.acc_args.weight.y = weightY;
|
||||
args.acc_fn_args.cap.x = capX;
|
||||
args.acc_fn_args.cap.y = capY;
|
||||
args.acc_fn_args.acc_args.offset = offset;
|
||||
args.acc_fn_args.acc_args.accel = accel;
|
||||
args.acc_fn_args.acc_args.limit = lim_exp;
|
||||
args.acc_fn_args.acc_args.exponent = lim_exp;
|
||||
args.acc_fn_args.acc_args.midpoint = midpoint;
|
||||
args.acc_fn_args.acc_args.gain_cap = gain_cap;
|
||||
mouse_modifier* const modifier_instance = new mouse_modifier();
|
||||
|
||||
replace(modifier_instance, args);
|
||||
WriteToDriver();
|
||||
}
|
||||
public:
|
||||
virtual ~ManagedAccel()
|
||||
{
|
||||
delete modifier_instance;
|
||||
}
|
||||
|
||||
double ManagedAccel::SensitivityX::get() { return modifier_instance->sensitivity.x; }
|
||||
double ManagedAccel::SensitivityY::get() { return modifier_instance->sensitivity.y; }
|
||||
double ManagedAccel::Rotation::get() { return atan(modifier_instance->rotate.rot_vec.y / modifier_instance->rotate.rot_vec.x) * 180 / M_PI; }
|
||||
int ManagedAccel::Type::get() { return modifier_instance->accel_fn.accel.tag; }
|
||||
double ManagedAccel::Acceleration::get() { return modifier_instance->accel_fn.impl_args.accel; }
|
||||
double ManagedAccel::CapX::get() { return modifier_instance->accel_fn.clamp.x.hi; }
|
||||
double ManagedAccel::CapY::get() { return modifier_instance->accel_fn.clamp.y.hi; }
|
||||
double ManagedAccel::GainCap::get() { return modifier_instance->accel_fn.gain_cap.threshold; }
|
||||
bool ManagedAccel::GainCapEnabled::get() { return modifier_instance->accel_fn.gain_cap.cap_gain_enabled; }
|
||||
double ManagedAccel::WeightX::get() { return modifier_instance->accel_fn.impl_args.weight.x; }
|
||||
double ManagedAccel::WeightY::get() { return modifier_instance->accel_fn.impl_args.weight.y; }
|
||||
double ManagedAccel::Offset::get() { return modifier_instance->accel_fn.speed_offset; }
|
||||
double ManagedAccel::LimitExp::get() { return modifier_instance->accel_fn.impl_args.limit; }
|
||||
double ManagedAccel::Midpoint::get() { return modifier_instance->accel_fn.impl_args.midpoint; }
|
||||
double ManagedAccel::MinimumTime::get() { return modifier_instance->accel_fn.time_min; }
|
||||
double ManagedAccel::PowerScale::get() { return modifier_instance->accel_fn.impl_args.power_scale; }
|
||||
!ManagedAccel()
|
||||
{
|
||||
delete modifier_instance;
|
||||
}
|
||||
|
||||
void ManagedAccel::WriteToDriver()
|
||||
{
|
||||
wrapper_io::writeToDriver(*modifier_instance);
|
||||
}
|
||||
Tuple<double, double>^ Accelerate(int x, int y, double time)
|
||||
{
|
||||
vec2d in_out_vec = {
|
||||
(double)x,
|
||||
(double)y
|
||||
};
|
||||
modifier_instance->modify(in_out_vec, time);
|
||||
|
||||
void ManagedAccel::ReadFromDriver()
|
||||
{
|
||||
wrapper_io::readFromDriver(*modifier_instance);
|
||||
}
|
||||
return gcnew Tuple<double, double>(in_out_vec.x, in_out_vec.y);
|
||||
}
|
||||
|
||||
void UpdateFromSettings(IntPtr argsIn)
|
||||
{
|
||||
*modifier_instance = { *reinterpret_cast<settings*>(argsIn.ToPointer()) };
|
||||
}
|
||||
|
||||
static ManagedAccel^ GetActiveAccel()
|
||||
{
|
||||
settings args;
|
||||
wrapper_io::readFromDriver(args);
|
||||
|
||||
auto active = gcnew ManagedAccel();
|
||||
*active->modifier_instance = { args };
|
||||
return active;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "wrapper_io.hpp"
|
||||
|
||||
using namespace System;
|
||||
|
||||
public ref class ManagedAccel
|
||||
{
|
||||
mouse_modifier* const modifier_instance;
|
||||
|
||||
public:
|
||||
|
||||
ManagedAccel(System::IntPtr args) :
|
||||
modifier_instance(new mouse_modifier(*reinterpret_cast<modifier_args*>(args.ToPointer())))
|
||||
{}
|
||||
|
||||
// Empty constructor needed for serialization
|
||||
ManagedAccel() : modifier_instance(nullptr) {}
|
||||
|
||||
virtual ~ManagedAccel()
|
||||
{
|
||||
if (modifier_instance != nullptr)
|
||||
{
|
||||
delete modifier_instance;
|
||||
}
|
||||
}
|
||||
|
||||
!ManagedAccel()
|
||||
{
|
||||
if (modifier_instance != nullptr)
|
||||
{
|
||||
delete modifier_instance;
|
||||
}
|
||||
}
|
||||
|
||||
// Duplicate all relevant rawaccel struct members here for access and display in GUI
|
||||
property double SensitivityX { double get(); }
|
||||
property double SensitivityY { double get(); }
|
||||
property double Rotation { double get(); }
|
||||
property int Type { int get(); }
|
||||
property double Acceleration { double get(); }
|
||||
property bool GainCapEnabled { bool get(); }
|
||||
property double CapX { double get(); }
|
||||
property double CapY { double get(); }
|
||||
property double GainCap { double get(); }
|
||||
property double WeightX { double get(); }
|
||||
property double WeightY { double get(); }
|
||||
property double Offset { double get(); }
|
||||
property double LimitExp { double get(); }
|
||||
property double Midpoint { double get(); }
|
||||
property double MinimumTime { double get(); }
|
||||
property double PowerScale { double get(); }
|
||||
|
||||
Tuple<double, double>^ Accelerate(int x, int y, double time);
|
||||
|
||||
void UpdateAccel(
|
||||
int mode,
|
||||
double rotation,
|
||||
double sensitivityX,
|
||||
double sensitivityY,
|
||||
double weightX,
|
||||
double weightY,
|
||||
double capX,
|
||||
double capY,
|
||||
double offset,
|
||||
double accel,
|
||||
double lim_exp,
|
||||
double midpoint,
|
||||
double gain_cap);
|
||||
|
||||
void WriteToDriver();
|
||||
|
||||
void ReadFromDriver();
|
||||
};
|
|
@ -68,7 +68,6 @@
|
|||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="wrapper.hpp" />
|
||||
<ClInclude Include="wrapper_io.hpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="wrapper.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="wrapper_io.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -3,12 +3,38 @@
|
|||
#include <rawaccel-io.hpp>
|
||||
#include "wrapper_io.hpp"
|
||||
|
||||
void wrapper_io::writeToDriver(const mouse_modifier& modifier)
|
||||
void wrapper_io::writeToDriver(const settings& args)
|
||||
{
|
||||
write(modifier);
|
||||
try
|
||||
{
|
||||
write(args);
|
||||
}
|
||||
catch (const cooldown_error&)
|
||||
{
|
||||
throw gcnew DriverWriteCDException();
|
||||
}
|
||||
catch (const install_error&)
|
||||
{
|
||||
throw gcnew DriverNotInstalledException();
|
||||
}
|
||||
catch (const std::system_error& e)
|
||||
{
|
||||
throw gcnew DriverIOException(gcnew String(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
void wrapper_io::readFromDriver(mouse_modifier& modifier)
|
||||
void wrapper_io::readFromDriver(settings& args)
|
||||
{
|
||||
modifier = read();
|
||||
try
|
||||
{
|
||||
args = read();
|
||||
}
|
||||
catch (const install_error&)
|
||||
{
|
||||
throw gcnew DriverNotInstalledException();
|
||||
}
|
||||
catch (const std::system_error& e)
|
||||
{
|
||||
throw gcnew DriverIOException(gcnew String(e.what()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include <rawaccel.hpp>
|
||||
#include <rawaccel-settings.h>
|
||||
|
||||
using namespace rawaccel;
|
||||
using namespace System;
|
||||
|
||||
struct wrapper_io {
|
||||
static void writeToDriver(const mouse_modifier& modifier);
|
||||
static void readFromDriver(mouse_modifier& modifier);
|
||||
static void writeToDriver(const settings&);
|
||||
static void readFromDriver(settings&);
|
||||
};
|
||||
|
||||
public ref struct DriverIOException : public IO::IOException {
|
||||
public:
|
||||
DriverIOException() {}
|
||||
DriverIOException(String^ what) : IO::IOException(what) {}
|
||||
};
|
||||
|
||||
public ref struct DriverNotInstalledException : public DriverIOException {};
|
||||
|
||||
public ref struct DriverWriteCDException : public DriverIOException {};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue