Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,18 @@ The more general function, which is relevant with a set input offset, is:

$$(dx_f, dy_f) = (dx_0, dy_0) * (1 + a * (V - offset_in)^2 / V)$$

## Classic Acceleration Function

Classic mode generalizes the linear formula with a configurable exponent:

$$(dx_f, dy_f) = (dx_0, dy_0) * (1 + a * (V - offset_in)^e / V)$$

The default exponent is `2`, matching the existing linear behavior. Values above
`2` ramp up more aggressively at higher input speeds.

## Other Curves

- [x] **Classic**
- [x] **Natural**
![image](https://github.com/user-attachments/assets/d14d0fa3-f762-4ad6-911c-cf564227d1ac)

Expand Down
3 changes: 3 additions & 0 deletions README_NIXOS.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ Create your `maccel.nix` module:
offset = 2.0;
outputCap = 2.0;

# Classic mode
exponent = 2.5;

# Natural mode
decayRate = 0.1;
offset = 2.0;
Expand Down
13 changes: 11 additions & 2 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use maccel_core::{
fixedptc::Fpt,
persist::{ParamStore, SysFsStore},
subcommads::*,
AccelMode, NoAccelParamArgs, Param, ALL_COMMON_PARAMS, ALL_LINEAR_PARAMS, ALL_NATURAL_PARAMS,
ALL_SYNCHRONOUS_PARAMS,
AccelMode, NoAccelParamArgs, Param, ALL_CLASSIC_PARAMS, ALL_COMMON_PARAMS, ALL_LINEAR_PARAMS,
ALL_NATURAL_PARAMS, ALL_SYNCHRONOUS_PARAMS,
};
use maccel_tui::run_tui;

Expand Down Expand Up @@ -78,6 +78,9 @@ fn main() -> anyhow::Result<()> {
SetParamByModesSubcommands::Synchronous(param_args) => {
param_store.set_all_synchronous(param_args)?
}
SetParamByModesSubcommands::Classic(param_args) => {
param_store.set_all_classic(param_args)?
}
SetParamByModesSubcommands::NoAccel(NoAccelParamArgs {}) => {
eprintln!(
"NOTE: There are no parameters specific here except for the common ones."
Expand Down Expand Up @@ -110,6 +113,9 @@ fn main() -> anyhow::Result<()> {
GetParamsByModesSubcommands::Synchronous => {
print_all_params(ALL_SYNCHRONOUS_PARAMS.iter(), oneline, quiet)?;
}
GetParamsByModesSubcommands::Classic => {
print_all_params(ALL_CLASSIC_PARAMS.iter(), oneline, quiet)?;
}
GetParamsByModesSubcommands::NoAccel => {
eprintln!(
"NOTE: There are no parameters specific here except for the common ones."
Expand All @@ -131,6 +137,9 @@ fn main() -> anyhow::Result<()> {
AccelMode::Synchronous => {
print_all_params(ALL_SYNCHRONOUS_PARAMS.iter(), false, false)?;
}
AccelMode::Classic => {
print_all_params(ALL_CLASSIC_PARAMS.iter(), false, false)?;
}
AccelMode::NoAccel => {
eprintln!(
"NOTE: There are no parameters specific here except for the common ones."
Expand Down
4 changes: 4 additions & 0 deletions crates/core/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ impl<PS: ParamStore> TuiContext<PS> {
offset_linear: get!(OffsetLinear),
offset_natural: get!(OffsetNatural),
output_cap: get!(OutputCap),
classic_accel: get!(ClassicAccel),
offset_classic: get!(OffsetClassic),
classic_output_cap: get!(ClassicOutputCap),
classic_exponent: get!(ClassicExponent),
decay_rate: get!(DecayRate),
limit: get!(Limit),
gamma: get!(Gamma),
Expand Down
36 changes: 33 additions & 3 deletions crates/core/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@ declare_params!(
SyncSpeed,
},
NoAccel {},
Classic {
ClassicAccel,
OffsetClassic,
ClassicOutputCap,
ClassicExponent,
},
);

impl AccelMode {
Expand All @@ -202,6 +208,7 @@ impl AccelMode {
AccelMode::Natural => "Natural (w/ Gain)",
AccelMode::Synchronous => "Synchronous",
AccelMode::NoAccel => "No Acceleration",
AccelMode::Classic => "Classic Acceleration",
}
}
}
Expand All @@ -226,6 +233,10 @@ impl Param {
Param::OffsetLinear => "OFFSET",
Param::OffsetNatural => "OFFSET",
Param::OutputCap => "OUTPUT_CAP",
Param::ClassicAccel => "ACCEL",
Param::OffsetClassic => "OFFSET",
Param::ClassicOutputCap => "OUTPUT_CAP",
Param::ClassicExponent => "EXPONENT",
Param::DecayRate => "DECAY_RATE",
Param::Limit => "LIMIT",
Param::Gamma => "GAMMA",
Expand All @@ -244,6 +255,10 @@ impl Param {
Param::OffsetLinear => "Offset",
Param::OffsetNatural => "Offset",
Param::OutputCap => "Output-Cap",
Param::ClassicAccel => "Accel",
Param::OffsetClassic => "Offset",
Param::ClassicOutputCap => "Output-Cap",
Param::ClassicExponent => "Exponent",
Param::YxRatio => "Y/x Ratio",
Param::DecayRate => "Decay-Rate",
Param::Limit => "Limit",
Expand All @@ -268,6 +283,16 @@ impl Param {
Param::Accel => "Acceleration strength. Higher values = faster cursor at high speeds.",
Param::OffsetLinear => "Speed threshold (counts/ms) before acceleration begins.",
Param::OutputCap => "Maximum sensitivity multiplier cap. Prevents excessive speed.",
Param::ClassicAccel => {
"Acceleration strength for the Classic curve. Higher values = faster cursor at high speeds."
}
Param::OffsetClassic => "Speed threshold (counts/ms) before Classic acceleration begins.",
Param::ClassicOutputCap => {
"Maximum sensitivity multiplier cap for the Classic curve."
}
Param::ClassicExponent => {
"Exponent controlling the Classic curve shape. Values above 2 ramp up more aggressively."
}
Param::DecayRate => "How quickly acceleration decays. Higher = faster decay.",
Param::OffsetNatural => "Speed threshold (counts/ms) for natural curve activation.",
Param::Limit => "Maximum gain limit for natural acceleration.",
Expand Down Expand Up @@ -316,13 +341,18 @@ pub(crate) fn validate_param_value(param_tag: Param, value: f64) -> anyhow::Resu
}
}
Param::AngleRotation => {}
Param::Accel => {}
Param::OutputCap => {}
Param::OffsetLinear | Param::OffsetNatural => {
Param::Accel | Param::ClassicAccel => {}
Param::OutputCap | Param::ClassicOutputCap => {}
Param::OffsetLinear | Param::OffsetNatural | Param::OffsetClassic => {
if value < 0.0 {
anyhow::bail!("offset cannot be less than 0");
}
}
Param::ClassicExponent => {
if value <= 0.0 {
anyhow::bail!("Classic exponent must be positive");
}
}
Param::DecayRate => {
if value <= 0.0 {
anyhow::bail!("decay rate must be positive");
Expand Down
20 changes: 18 additions & 2 deletions crates/core/src/persist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use anyhow::{Context, anyhow};
use crate::{
fixedptc::Fpt,
params::{
ALL_MODES, AccelMode, CommonParamArgs, LinearParamArgs, NaturalParamArgs, Param,
SynchronousParamArgs, format_param_value, validate_param_value,
ALL_MODES, AccelMode, ClassicParamArgs, CommonParamArgs, LinearParamArgs,
NaturalParamArgs, Param, SynchronousParamArgs, format_param_value, validate_param_value,
},
};

Expand Down Expand Up @@ -131,6 +131,22 @@ impl SysFsStore {

Ok(())
}

pub fn set_all_classic(&mut self, args: ClassicParamArgs) -> anyhow::Result<()> {
let ClassicParamArgs {
classic_accel,
offset_classic,
classic_output_cap,
classic_exponent,
} = args;

self.set(Param::ClassicAccel, classic_accel)?;
self.set(Param::OffsetClassic, offset_classic)?;
self.set(Param::ClassicOutputCap, classic_output_cap)?;
self.set(Param::ClassicExponent, classic_exponent)?;

Ok(())
}
}

fn parameter_path(name: &'static str) -> anyhow::Result<PathBuf> {
Expand Down
9 changes: 8 additions & 1 deletion crates/core/src/sens_fns.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{
AccelParams, AccelParamsByMode, LinearCurveParams, NaturalCurveParams, SynchronousCurveParams,
AccelParams, AccelParamsByMode, ClassicCurveParams, LinearCurveParams, NaturalCurveParams,
SynchronousCurveParams,
libmaccel::{self, fixedptc::Fpt},
params::AllParamArgs,
};
Expand Down Expand Up @@ -28,6 +29,12 @@ impl AllParamArgs {
AccelMode::NoAccel => {
AccelParamsByMode::NoAccel(crate::params::NoAccelCurveParams { _ffi_guard: [] })
}
AccelMode::Classic => AccelParamsByMode::Classic(ClassicCurveParams {
classic_accel: self.classic_accel,
offset_classic: self.offset_classic,
classic_output_cap: self.classic_output_cap,
classic_exponent: self.classic_exponent,
}),
};

AccelParams {
Expand Down
8 changes: 7 additions & 1 deletion driver/accel.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef _ACCEL_H_
#define _ACCEL_H_

#include "accel/classic.h"
#include "accel/linear.h"
#include "accel/mode.h"
#include "accel/natural.h"
Expand All @@ -17,6 +18,7 @@ union __accel_args {
struct linear_curve_args linear;
struct synchronous_curve_args synchronous;
struct no_accel_curve_args no_accel;
struct classic_curve_args classic;
};

struct accel_args {
Expand All @@ -25,7 +27,7 @@ struct accel_args {
fpt input_dpi;
fpt angle_rotation_deg;

enum accel_mode tag;
unsigned char tag;
union __accel_args args;
};

Expand Down Expand Up @@ -57,6 +59,10 @@ static inline struct vector sensitivity(fpt input_speed,
dbg("accel mode %d: no_accel", args.tag);
sens = FIXEDPT_ONE;
break;
case classic:
dbg("accel mode %d: classic", args.tag);
sens = __classic_sens_fun(input_speed, args.args.classic);
break;
default:
sens = FIXEDPT_ONE;
}
Expand Down
61 changes: 61 additions & 0 deletions driver/accel/classic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#ifndef __ACCEL_CLASSIC_H_
#define __ACCEL_CLASSIC_H_

#include "../dbg.h"
#include "../fixedptc.h"
#include "../math.h"

struct classic_curve_args {
fpt accel;
fpt offset;
fpt output_cap;
fpt exponent;
};

static inline fpt classic_power(fpt base, fpt exponent) {
if (exponent == FIXEDPT_TWO) {
return fpt_mul(base, base);
}

return fpt_pow(base, exponent);
}

static inline fpt classic_base_fn(fpt x, fpt accel, fpt input_offset,
fpt exponent) {
fpt _x = x - input_offset;
fpt powered_x = classic_power(_x, exponent);
return fpt_mul(accel, fpt_div(powered_x, x));
}

/**
* Sensitivity Function for Classic Acceleration
*/
static inline fpt __classic_sens_fun(fpt input_speed,
struct classic_curve_args args) {
dbg("classic: accel %s", fptoa(args.accel));
dbg("classic: offset %s", fptoa(args.offset));
dbg("classic: output_cap %s", fptoa(args.output_cap));
dbg("classic: exponent %s", fptoa(args.exponent));

if (input_speed == 0 || input_speed <= args.offset || args.exponent <= 0) {
return FIXEDPT_ONE;
}

fpt sens =
classic_base_fn(input_speed, args.accel, args.offset, args.exponent);
dbg("classic: base_fn sens %s", fptoa(sens));

fpt sign = FIXEDPT_ONE;
if (args.output_cap > 0) {
fpt cap = fpt_sub(args.output_cap, FIXEDPT_ONE);
if (cap < 0) {
cap = -cap;
sign = -sign;
}
sens = minsd(sens, cap);
}

return fpt_add(FIXEDPT_ONE, fpt_mul(sign, sens));
}

#endif // !__ACCEL_CLASSIC_H_
2 changes: 1 addition & 1 deletion driver/accel/mode.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#ifndef __ACCEL_MODE_H
#define __ACCEL_MODE_H

enum accel_mode : unsigned char { linear, natural, synchronous, no_accel };
enum accel_mode { linear, natural, synchronous, no_accel, classic };

#endif // !__ACCEL_MODE_H
8 changes: 8 additions & 0 deletions driver/accel_k.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define _ACCELK_H_

#include "accel.h"
#include "accel/classic.h"
#include "accel/linear.h"
#include "accel/mode.h"
#include "fixedptc.h"
Expand Down Expand Up @@ -40,6 +41,13 @@ static struct accel_args collect_args(void) {
accel.args.linear.output_cap = atofp(PARAM_OUTPUT_CAP);
break;
}
case classic: {
accel.args.classic.accel = atofp(PARAM_ACCEL);
accel.args.classic.offset = atofp(PARAM_OFFSET);
accel.args.classic.output_cap = atofp(PARAM_OUTPUT_CAP);
accel.args.classic.exponent = atofp(PARAM_EXPONENT);
break;
}
case no_accel:
default: {
}
Expand Down
10 changes: 10 additions & 0 deletions driver/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ PARAM(ACCEL, 0, "Control the sensitivity calculation.");
PARAM(OFFSET, 0, "Input speed threshold (counts/ms) before acceleration begins.");
PARAM(OUTPUT_CAP, 0, "Control the maximum sensitivity.");

// For Classic Mode

#if FIXEDPT_BITS == 64
PARAM(EXPONENT, 8589934592, // 2 << 32
"Exponent of the Classic acceleration curve.");
#else
PARAM(EXPONENT, 131072, // 2 << 16
"Exponent of the Classic acceleration curve.");
#endif

// For Natural Mode

#if FIXEDPT_BITS == 64
Expand Down
Loading