summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authora1xd <[email protected]>2021-04-08 02:30:01 -0400
committera1xd <[email protected]>2021-04-08 02:30:01 -0400
commitc55d1bfd01147fa014ac07d4b03ef3cad8427ae6 (patch)
tree39ffa4a79bc6b019443521f10203f787c4b98698
parentunmark fill as const (diff)
downloadrawaccel-c55d1bfd01147fa014ac07d4b03ef3cad8427ae6.tar.xz
rawaccel-c55d1bfd01147fa014ac07d4b03ef3cad8427ae6.zip
optimize a bit/refactor modify
-rw-r--r--common/accel-invoke.hpp11
-rw-r--r--common/accel-jump.hpp5
-rw-r--r--common/accel-natural.hpp8
-rw-r--r--common/rawaccel-base.hpp5
-rw-r--r--common/rawaccel-validate.hpp12
-rw-r--r--common/rawaccel.hpp323
-rw-r--r--common/utility.hpp27
-rw-r--r--driver/driver.cpp33
-rw-r--r--driver/driver.vcxproj12
-rw-r--r--wrapper/wrapper.vcxproj2
10 files changed, 189 insertions, 249 deletions
diff --git a/common/accel-invoke.hpp b/common/accel-invoke.hpp
index 0e264c1..f2a95dc 100644
--- a/common/accel-invoke.hpp
+++ b/common/accel-invoke.hpp
@@ -20,7 +20,16 @@ namespace rawaccel {
accel_invoker(const accel_args& args)
{
cb = visit_accel([](auto&& arg) {
- return &invoke_impl<remove_ref_t<decltype(arg)>>;
+ using T = remove_ref_t<decltype(arg)>;
+
+ if constexpr (is_same_v<T, motivity>) {
+ static_assert(sizeof motivity == sizeof binlog_lut);
+ return &invoke_impl<binlog_lut>;
+ }
+ else {
+ return &invoke_impl<T>;
+ }
+
}, make_mode(args), accel_union{});
}
diff --git a/common/accel-jump.hpp b/common/accel-jump.hpp
index 2d13cae..30f9a49 100644
--- a/common/accel-jump.hpp
+++ b/common/accel-jump.hpp
@@ -2,9 +2,6 @@
#include "rawaccel-base.hpp"
-#define _USE_MATH_DEFINES
-#include <math.h>
-
namespace rawaccel {
struct jump_base {
@@ -18,7 +15,7 @@ namespace rawaccel {
smooth_rate = 0;
}
else {
- smooth_rate = 2 * M_PI / (args.offset * args.smooth);
+ smooth_rate = 2 * PI / (args.offset * args.smooth);
}
}
diff --git a/common/accel-natural.hpp b/common/accel-natural.hpp
index 28e17c2..8d25351 100644
--- a/common/accel-natural.hpp
+++ b/common/accel-natural.hpp
@@ -26,8 +26,8 @@ namespace rawaccel {
{
if (x <= offset) return 1;
- double offset_x = x - offset;
- double decay = exp(-accel * offset_x);
+ double offset_x = offset - x;
+ double decay = exp(accel * offset_x);
return limit * (1 - (decay * offset_x + offset) / x) + 1;
}
@@ -41,8 +41,8 @@ namespace rawaccel {
{
if (x <= offset) return 1;
- double offset_x = x - offset;
- double decay = exp(-accel * offset_x);
+ double offset_x = offset - x;
+ double decay = exp(accel * offset_x);
double output = limit * (offset_x + decay / accel) + constant;
return output / x + 1;
}
diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp
index 6ce4468..dde56f5 100644
--- a/common/rawaccel-base.hpp
+++ b/common/rawaccel-base.hpp
@@ -17,6 +17,9 @@ namespace rawaccel {
inline constexpr size_t LUT_CAPACITY = 1025;
+ inline constexpr double MAX_NORM = 16;
+ inline constexpr double PI = 3.14159265358979323846;
+
enum class accel_mode {
classic,
jump,
@@ -79,7 +82,7 @@ namespace rawaccel {
vec2<accel_args> argsv;
vec2d sens = { 1, 1 };
- vec2d dir_multipliers = {};
+ vec2d dir_multipliers = { 1, 1 };
domain_args dom_args = {};
vec2d range_weights = { 1, 1 };
diff --git a/common/rawaccel-validate.hpp b/common/rawaccel-validate.hpp
index 230ddac..4f7dd9c 100644
--- a/common/rawaccel-validate.hpp
+++ b/common/rawaccel-validate.hpp
@@ -141,6 +141,10 @@ namespace rawaccel {
error("max speed is less than min speed");
}
+ if (args.degrees_snap < 0 || args.degrees_snap > 45) {
+ error("snap angle must be between 0 and 45 degrees");
+ }
+
if (args.sens.x == 0 || args.sens.y == 0) {
error("sens multiplier is 0");
}
@@ -150,12 +154,12 @@ namespace rawaccel {
error("domain weights"" must be positive");
}
- if (args.dom_args.lp_norm <= 0) {
- error("Lp norm must be positive");
+ if (args.dir_multipliers.x <= 0 || args.dir_multipliers.y <= 0) {
+ error("directional multipliers must be positive");
}
- if (args.dir_multipliers.x < 0 || args.dir_multipliers.y < 0) {
- error("directional multipliers can not be negative");
+ if (args.dom_args.lp_norm < 2) {
+ error("Lp norm is less than 2 (default=2)");
}
if (args.range_weights.x <= 0 || args.range_weights.y <= 0) {
diff --git a/common/rawaccel.hpp b/common/rawaccel.hpp
index 6710a0c..fb2d81a 100644
--- a/common/rawaccel.hpp
+++ b/common/rawaccel.hpp
@@ -2,235 +2,170 @@
#include "accel-invoke.hpp"
-#define _USE_MATH_DEFINES
-#include <math.h>
-
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 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
- };
- }
-
- rotator(double degrees) {
- double rads = degrees * M_PI / 180;
- rot_vec = { cos(rads), sin(rads) };
- }
-
- rotator() = default;
- };
-
- struct snapper {
- double threshold = 0;
-
- inline vec2d apply(const vec2d& input) const {
- if (input.x != 0 && input.y != 0) {
- double angle = fabs(atan(input.y / input.x));
- auto mag = [&] { return sqrtsd(input.x * input.x + input.y * input.y); };
-
- if (angle > M_PI_2 - threshold) return { 0, _copysign(mag(), input.y) };
- if (angle < threshold) return { _copysign(mag(), input.x), 0 };
- }
-
- return input;
- }
-
- snapper(double degrees) : threshold(minsd(fabs(degrees), 45)* M_PI / 180) {}
-
- snapper() = default;
- };
-
- inline void clamp_speed(vec2d& v, double min, double max, double norm) {
- double speed = sqrtsd(v.x * v.x + v.y * v.y) * norm;
- double ratio = clampsd(speed, min, max) / speed;
- v.x *= ratio;
- v.y *= ratio;
+ inline vec2d direction(double degrees)
+ {
+ double radians = degrees * PI / 180;
+ return { cos(radians), sin(radians) };
}
- struct weighted_distance {
- double p = 2.0;
- double p_inverse = 0.5;
- bool lp_norm_infinity = false;
- double sigma_x = 1.0;
- double sigma_y = 1.0;
-
- weighted_distance(const domain_args& args)
- {
- sigma_x = args.domain_weights.x;
- sigma_y = args.domain_weights.y;
- if (args.lp_norm <= 0)
- {
- lp_norm_infinity = true;
- p = 0.0;
- p_inverse = 0.0;
- }
- else
- {
- lp_norm_infinity = false;
- p = args.lp_norm;
- p_inverse = 1 / args.lp_norm;
- }
- }
-
- inline double calculate(double x, double y)
- {
- double abs_scaled_x = fabs(x) * sigma_x;
- double abs_scaled_y = fabs(y) * sigma_y;
-
- if (lp_norm_infinity) {
- return maxsd(abs_scaled_x, abs_scaled_y);
- }
-
- if (p == 2) {
- return sqrtsd(abs_scaled_x * abs_scaled_x +
- abs_scaled_y * abs_scaled_y);
- }
-
- double dist_p = pow(abs_scaled_x, p) + pow(abs_scaled_y, p);
- return pow(dist_p, p_inverse);
- }
+ constexpr vec2d rotate(const vec2d& v, const vec2d& direction)
+ {
+ return {
+ v.x * direction.x - v.y * direction.y,
+ v.x * direction.y + v.y * direction.x
+ };
+ }
- weighted_distance() = default;
- };
+ inline double magnitude(const vec2d& v)
+ {
+ return sqrt(v.x * v.x + v.y * v.y);
+ }
- inline double directional_weight(const vec2d& in, const vec2d& weights)
+ inline double lp_distance(const vec2d& v, double p)
{
- double atan_scale = M_2_PI * atan2(fabs(in.y), fabs(in.x));
- return atan_scale * (weights.y - weights.x) + weights.x;
+ return pow(pow(v.x, p) + pow(v.y, p), 1 / p);
}
- /// <summary> Struct to hold variables and methods for modifying mouse input </summary>
- struct mouse_modifier {
+ class mouse_modifier {
+ public:
+ enum accel_distance_mode : unsigned char {
+ separate,
+ max,
+ Lp,
+ euclidean,
+ };
+
bool apply_rotate = false;
+ bool compute_ref_angle = false;
bool apply_snap = false;
- bool apply_speed_clamp = false;
- bool by_component = false;
+ bool cap_speed = false;
+ accel_distance_mode dist_mode = euclidean;
bool apply_directional_weight = false;
- rotator rotate;
- snapper snap;
- double dpi_factor = 1;
+ bool apply_dir_mul_x = false;
+ bool apply_dir_mul_y = false;
+
+ vec2d rot_vec = { 1, 0 };
+ double snap = 0;
+ double dpi_norm_factor = 1;
double speed_min = 0;
double speed_max = 0;
- weighted_distance distance;
+ vec2d domain_weights = { 1, 1 };
+ double p = 2;
vec2d range_weights = { 1, 1 };
- vec2<accel_union> accels;
+ vec2d directional_multipliers = { 1, 1 };
vec2d sensitivity = { 1, 1 };
- vec2d directional_multipliers = {};
+ vec2<accel_union> accel;
- mouse_modifier(const settings& args) :
- by_component(!args.combine_mags),
- dpi_factor(1000 / args.dpi),
- speed_min(args.speed_min),
- speed_max(args.speed_max),
- range_weights(args.range_weights)
+#ifdef _KERNEL_MODE
+ __forceinline
+#endif
+ void modify(vec2d& in, const vec2<accel_invoker>& inv, milliseconds time = 1) const
{
- if (args.degrees_rotation != 0) {
- rotate = rotator(args.degrees_rotation);
- apply_rotate = true;
- }
-
- if (args.degrees_snap != 0) {
- snap = snapper(args.degrees_snap);
- apply_snap = true;
- }
-
- if (args.sens.x != 0) sensitivity.x = args.sens.x;
- if (args.sens.y != 0) sensitivity.y = args.sens.y;
+ double ips_factor = dpi_norm_factor / time;
+ double reference_angle = 0;
- directional_multipliers.x = fabs(args.dir_multipliers.x);
- directional_multipliers.y = fabs(args.dir_multipliers.y);
+ if (apply_rotate) in = rotate(in, rot_vec);
- apply_speed_clamp = speed_max > 0;
-
- if ((!by_component && args.argsv.x.mode == accel_mode::noaccel) ||
- (args.argsv.x.mode == accel_mode::noaccel &&
- args.argsv.y.mode == accel_mode::noaccel)) {
- return;
+ if (compute_ref_angle && in.y != 0) {
+ if (in.x == 0) {
+ reference_angle = PI / 2;
+ }
+ else {
+ reference_angle = atan(fabs(in.y / in.x));
+
+ if (apply_snap) {
+ if (reference_angle > PI / 2 - snap) {
+ reference_angle = PI / 2;
+ in = { 0, _copysign(magnitude(in), in.y) };
+ }
+ else if (reference_angle < snap) {
+ reference_angle = 0;
+ in = { _copysign(magnitude(in), in.x), 0 };
+ }
+ }
+ }
}
- accels.x = accel_union(args.argsv.x);
- accels.y = accel_union(args.argsv.y);
-
- distance = weighted_distance(args.dom_args);
-
- apply_directional_weight = range_weights.x != range_weights.y;
- }
-
- void modify(vec2d& movement, const vec2<accel_invoker>& inv = {}, milliseconds time = 1) {
- apply_rotation(movement);
- apply_angle_snap(movement);
- apply_acceleration(movement, inv, time);
- apply_sensitivity(movement);
- }
-
- inline void apply_rotation(vec2d& movement) {
- if (apply_rotate) movement = rotate.apply(movement);
- }
-
- inline void apply_angle_snap(vec2d& movement) {
- if (apply_snap) movement = snap.apply(movement);
- }
-
- inline void apply_acceleration(vec2d& movement, const vec2<accel_invoker>& inv, milliseconds time) {
- double norm = dpi_factor / time;
-
- if (apply_speed_clamp) {
- clamp_speed(movement, speed_min, speed_max, norm);
+ if (cap_speed) {
+ double speed = magnitude(in) * ips_factor;
+ double ratio = clampsd(speed, speed_min, speed_max) / speed;
+ in.x *= ratio;
+ in.y *= ratio;
}
- if (!by_component) {
- double mag = distance.calculate(movement.x, movement.y);
- double speed = mag * norm;
+ vec2d abs_weighted_vel = {
+ fabs(in.x * ips_factor * domain_weights.x),
+ fabs(in.y * ips_factor * domain_weights.y)
+ };
- double weight;
+ if (dist_mode == separate) {
+ in.x *= inv.x.invoke(accel.x, abs_weighted_vel.x, range_weights.x);
+ in.y *= inv.y.invoke(accel.y, abs_weighted_vel.y, range_weights.y);
+ }
+ else {
+ double speed;
- if (apply_directional_weight) {
- weight = directional_weight(movement, range_weights);
+ if (dist_mode == max) {
+ speed = maxsd(abs_weighted_vel.x, abs_weighted_vel.y);
+ }
+ else if (dist_mode == Lp) {
+ speed = lp_distance(abs_weighted_vel, p);
}
else {
- weight = range_weights.x;
+ speed = magnitude(abs_weighted_vel);
}
- double scale = inv.x.invoke(accels.x, speed, weight);
- movement.x *= scale;
- movement.y *= scale;
- }
- else {
- if (movement.x != 0) {
- double x = fabs(movement.x) * norm * distance.sigma_x;
- movement.x *= inv.x.invoke(accels.x, x, range_weights.x);
- }
- if (movement.y != 0) {
- double y = fabs(movement.y) * norm * distance.sigma_y;
- movement.y *= inv.y.invoke(accels.y, y, range_weights.y);
+ double weight = range_weights.x;
+
+ if (apply_directional_weight) {
+ double diff = range_weights.y - range_weights.x;
+ weight += 2 / PI * reference_angle * diff;
}
- }
- }
-
- inline void apply_sensitivity(vec2d& movement) {
- movement.x *= sensitivity.x;
- movement.y *= sensitivity.y;
+ double scale = inv.x.invoke(accel.x, speed, weight);
+ in.x *= scale;
+ in.y *= scale;
+ }
- if (directional_multipliers.x > 0 && movement.x < 0) {
- movement.x *= directional_multipliers.x;
+ if (apply_dir_mul_x && in.x < 0) {
+ in.x *= directional_multipliers.x;
}
- if (directional_multipliers.y > 0 && movement.y < 0) {
- movement.y *= directional_multipliers.y;
+
+ if (apply_dir_mul_y && in.y < 0) {
+ in.y *= directional_multipliers.y;
}
+
+ in.x *= sensitivity.x;
+ in.y *= sensitivity.y;
+ }
+
+ mouse_modifier(const settings& args) :
+ rot_vec(direction(args.degrees_rotation)),
+ snap(args.degrees_snap * PI / 180),
+ dpi_norm_factor(1000 / args.dpi),
+ speed_min(args.speed_min),
+ speed_max(args.speed_max),
+ p(args.dom_args.lp_norm),
+ domain_weights(args.dom_args.domain_weights),
+ range_weights(args.range_weights),
+ directional_multipliers(args.dir_multipliers),
+ sensitivity(args.sens),
+ accel({ { args.argsv.x }, { args.argsv.y } })
+ {
+ cap_speed = speed_max > 0 && speed_min <= speed_max;
+ apply_rotate = rot_vec.x != 1;
+ apply_snap = snap != 0;
+ apply_directional_weight = range_weights.x != range_weights.y;
+ compute_ref_angle = apply_snap || apply_directional_weight;
+ apply_dir_mul_x = directional_multipliers.x != 1;
+ apply_dir_mul_y = directional_multipliers.y != 1;
+
+ if (!args.combine_mags) dist_mode = separate;
+ else if (p >= MAX_NORM) dist_mode = max;
+ else if (p > 2) dist_mode = Lp;
+ else dist_mode = euclidean;
}
mouse_modifier() = default;
diff --git a/common/utility.hpp b/common/utility.hpp
index a8e5f83..cbd19e3 100644
--- a/common/utility.hpp
+++ b/common/utility.hpp
@@ -1,24 +1,7 @@
#pragma once
-#ifdef _MANAGED
-#include <math.h>
-#else
-#include <emmintrin.h>
-#endif
-
namespace rawaccel {
-#ifdef _MANAGED
- inline double sqrtsd(double val) { return sqrt(val); }
-#else
- inline double sqrtsd(double val) {
- __m128d src = _mm_load_sd(&val);
- __m128d dst = _mm_sqrt_sd(src, src);
- _mm_store_sd(&val, dst);
- return val;
- }
-#endif
-
constexpr double minsd(double a, double b)
{
return (a < b) ? a : b;
@@ -92,4 +75,14 @@ namespace rawaccel {
template <typename T>
using remove_ref_t = typename remove_ref<T>::type;
+
+ template <typename T, typename U>
+ struct is_same { static constexpr bool value = false; };
+
+ template <typename T>
+ struct is_same<T, T> { static constexpr bool value = true; };
+
+ template <typename T, typename U>
+ inline constexpr bool is_same_v = is_same<T, U>::value;
+
}
diff --git a/driver/driver.cpp b/driver/driver.cpp
index fa2415d..feace77 100644
--- a/driver/driver.cpp
+++ b/driver/driver.cpp
@@ -23,6 +23,7 @@ struct {
extern "C" PULONG InitSafeBootMode;
+__declspec(guard(ignore))
VOID
RawaccelCallback(
IN PDEVICE_OBJECT DeviceObject,
@@ -56,26 +57,18 @@ Arguments:
auto num_packets = InputDataEnd - InputDataStart;
- bool any = num_packets > 0;
- bool rel_move = !(InputDataStart->Flags & MOUSE_MOVE_ABSOLUTE);
- bool dev_match = global.args.device_id[0] == 0 ||
- global.args.ignore ==
- bool(wcsncmp(devExt->dev_id, global.args.device_id, ra::MAX_DEV_ID_LEN));
-
- if (any && rel_move && dev_match) {
- milliseconds time;
-
- if (global.args.time_min == global.args.time_max) {
- time = global.args.time_min;
- }
- else {
- counter_t now = KeQueryPerformanceCounter(NULL).QuadPart;
- counter_t ticks = now - devExt->counter;
- devExt->counter = now;
- milliseconds t = ticks * global.tick_interval / num_packets;
- time = ra::clampsd(t, global.args.time_min, global.args.time_max);
- }
-
+ if (num_packets > 0 &&
+ !(InputDataStart->Flags & MOUSE_MOVE_ABSOLUTE) &&
+ (global.args.device_id[0] == 0 ||
+ bool(wcsncmp(devExt->dev_id, global.args.device_id, ra::MAX_DEV_ID_LEN)) ==
+ global.args.ignore)) {
+ counter_t now = KeQueryPerformanceCounter(NULL).QuadPart;
+ counter_t ticks = now - devExt->counter;
+ devExt->counter = now;
+ milliseconds raw_elapsed = ticks * global.tick_interval;
+ milliseconds time = ra::clampsd(raw_elapsed / num_packets,
+ global.args.time_min,
+ global.args.time_max);
auto it = InputDataStart;
do {
if (it->LastX || it->LastY) {
diff --git a/driver/driver.vcxproj b/driver/driver.vcxproj
index 9034680..c2e4629 100644
--- a/driver/driver.vcxproj
+++ b/driver/driver.vcxproj
@@ -30,6 +30,7 @@
<ConfigurationType>Driver</ConfigurationType>
<OverrideDefaultRuntimeLibrary>true</OverrideDefaultRuntimeLibrary>
<SpectreMitigation>Spectre</SpectreMitigation>
+ <Driver_SpectreMitigation>Spectre</Driver_SpectreMitigation>
</PropertyGroup>
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TargetVersion>Windows7</TargetVersion>
@@ -38,6 +39,7 @@
<DriverType>KMDF</DriverType>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
+ <Driver_SpectreMitigation>Spectre</Driver_SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
@@ -74,18 +76,18 @@
</RuntimeLibrary>
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
<CallingConvention>StdCall</CallingConvention>
- <AssemblerOutput>AssemblyAndSourceCode</AssemblerOutput>
+ <AssemblerOutput>AssemblyCode</AssemblerOutput>
<ExpandAttributedSource>false</ExpandAttributedSource>
<UseUnicodeForAssemblerListing>false</UseUnicodeForAssemblerListing>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions>
- <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+ <FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<WholeProgramOptimization>false</WholeProgramOptimization>
<BufferSecurityCheck>true</BufferSecurityCheck>
<ControlFlowGuard>Guard</ControlFlowGuard>
- <FloatingPointModel>Precise</FloatingPointModel>
+ <FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
<Link>
<LinkTimeCodeGeneration>
@@ -114,9 +116,11 @@
<RuntimeLibrary>
</RuntimeLibrary>
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
- <FloatingPointModel>Precise</FloatingPointModel>
+ <FloatingPointModel>Fast</FloatingPointModel>
<CallingConvention>StdCall</CallingConvention>
<Optimization>MaxSpeed</Optimization>
+ <ControlFlowGuard>Guard</ControlFlowGuard>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
diff --git a/wrapper/wrapper.vcxproj b/wrapper/wrapper.vcxproj
index 8de0cfb..cd121a2 100644
--- a/wrapper/wrapper.vcxproj
+++ b/wrapper/wrapper.vcxproj
@@ -57,6 +57,7 @@
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<LanguageStandard>stdcpp17</LanguageStandard>
+ <FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
<Link>
<AdditionalDependencies>User32.lib;</AdditionalDependencies>
@@ -70,6 +71,7 @@
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<LanguageStandard>stdcpp17</LanguageStandard>
+ <FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
<Link>
<AdditionalDependencies>User32.lib;</AdditionalDependencies>