Skip to content

Commit

Permalink
Mouse input: Approximate the old smoothing function
Browse files Browse the repository at this point in the history
  • Loading branch information
hrydgard committed Dec 14, 2023
1 parent 7b0ee54 commit d397635
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 32 deletions.
88 changes: 59 additions & 29 deletions Core/TiltEventProcessor.cpp
Expand Up @@ -34,6 +34,8 @@ void GenerateDPadEvent(int digitalX, int digitalY);
void GenerateActionButtonEvent(int digitalX, int digitalY);
void GenerateTriggerButtonEvent(int digitalX, int digitalY);

}

// deadzone is normalized - 0 to 1
// sensitivity controls how fast the deadzone reaches max value
inline float ApplyDeadzoneAxis(float x, float deadzone) {
Expand All @@ -51,32 +53,35 @@ inline float ApplyDeadzoneAxis(float x, float deadzone) {
}
}

inline void ApplyDeadzoneXY(float tiltX, float tiltY, float *adjustedTiltX, float *adjustedTiltY, float deadzone, bool circular) {

inline void ApplyDeadzoneXY(float x, float y, float *adjustedX, float *adjustedY, float deadzone, bool circular) {
if (circular) {
if (tiltX == 0.0f && tiltY == 0.0f) {
*adjustedTiltX = 0.0f;
*adjustedTiltY = 0.0f;
if (x == 0.0f && y == 0.0f) {
*adjustedX = 0.0f;
*adjustedY = 0.0f;
return;
}

float magnitude = sqrtf(tiltX * tiltX + tiltY * tiltY);
float magnitude = sqrtf(x * x + y * y);
if (magnitude <= deadzone + 0.00001f) {
*adjustedTiltX = 0.0f;
*adjustedTiltY = 0.0f;
*adjustedX = 0.0f;
*adjustedY = 0.0f;
return;
}

float factor = 1.0f / (1.0f - deadzone);
float newMagnitude = (magnitude - deadzone) * factor;

*adjustedTiltX = (tiltX / magnitude) * newMagnitude;
*adjustedTiltY = (tiltY / magnitude) * newMagnitude;
*adjustedX = (x / magnitude) * newMagnitude;
*adjustedY = (y / magnitude) * newMagnitude;
} else {
*adjustedTiltX = ApplyDeadzoneAxis(tiltX, deadzone);
*adjustedTiltY = ApplyDeadzoneAxis(tiltY, deadzone);
*adjustedX = ApplyDeadzoneAxis(x, deadzone);
*adjustedY = ApplyDeadzoneAxis(y, deadzone);
}
}

namespace TiltEventProcessor {

// Also clamps to -1.0..1.0.
// This applies a (circular if desired) inverse deadzone.
inline void ApplyInverseDeadzone(float x, float y, float *outX, float *outY, float inverseDeadzone, bool circular) {
Expand Down Expand Up @@ -310,39 +315,64 @@ namespace MouseEventProcessor {
// But, the cost isn't high.
std::mutex g_mouseMutex;

float g_mouseDeltaX = 0;
float g_mouseDeltaY = 0;
float g_mouseDeltaXAccum = 0;
float g_mouseDeltaYAccum = 0;

void ProcessDelta(float dx, float dy) {
std::unique_lock<std::mutex> lock(g_mouseMutex);
// Accumulate mouse deltas, for some kind of smoothing.
g_mouseDeltaX += dx;
g_mouseDeltaY += dy;
}
float g_mouseDeltaX;
float g_mouseDeltaY;

void MouseDeltaToAxes(double now, float *mx, float *my) {
std::unique_lock<std::mutex> lock(g_mouseMutex);
void DecayMouse(double now) {
g_mouseDeltaX = g_mouseDeltaXAccum;
g_mouseDeltaY = g_mouseDeltaYAccum;

const float decay = g_Config.fMouseSmoothing;

static double lastTime = 0.0f;
if (lastTime == 0.0) {
lastTime = now;
*mx = 0.0f;
*my = 0.0f;
return;
}
double dt = now - lastTime;
lastTime = now;

// Decay the mouse deltas. We do an approximation of the old polling.
// Should be able to use a smooth exponential here, when I get around to doing
// the math.
static double accumDt = 0.0;
accumDt += dt;
const double oldPollInterval = 1.0 / 250.0; // See Windows "PollControllers".
while (accumDt > oldPollInterval) {
accumDt -= oldPollInterval;
g_mouseDeltaXAccum *= decay;
g_mouseDeltaYAccum *= decay;
}
}

void ProcessDelta(double now, float dx, float dy) {
std::unique_lock<std::mutex> lock(g_mouseMutex);

// Accumulate mouse deltas, for some kind of smoothing.
g_mouseDeltaXAccum += dx;
g_mouseDeltaYAccum += dy;

DecayMouse(now);
}

void MouseDeltaToAxes(double now, float *mx, float *my) {
std::unique_lock<std::mutex> lock(g_mouseMutex);

float scaleFactor_x = g_display.dpi_scale_x * 0.1 * g_Config.fMouseSensitivity;
float scaleFactor_y = g_display.dpi_scale_y * 0.1 * g_Config.fMouseSensitivity;

*mx = clamp_value(g_mouseDeltaX * scaleFactor_x, -1.0f, 1.0f);
*my = clamp_value(g_mouseDeltaY * scaleFactor_y, -1.0f, 1.0f);
DecayMouse(now);

// TODO: Make configurable.
float mouseDeadZone = 0.1f;

float outX = clamp_value(g_mouseDeltaX * scaleFactor_x, -1.0f, 1.0f);
float outY = clamp_value(g_mouseDeltaY * scaleFactor_y, -1.0f, 1.0f);

// Decay the mouse deltas. This is where we should use dt.
float decay = expf(-dt * 50.0f * (1.0f - g_Config.fMouseSmoothing));
g_mouseDeltaX *= decay;
g_mouseDeltaY *= decay;
ApplyDeadzoneXY(outX, outY, mx, my, mouseDeadZone, true);
}

} // namespace
2 changes: 1 addition & 1 deletion Core/TiltEventProcessor.h
Expand Up @@ -19,7 +19,7 @@ extern float rawTiltAnalogY;

namespace MouseEventProcessor {

void ProcessDelta(float dx, float dy);
void ProcessDelta(double now, float dx, float dy);
void MouseDeltaToAxes(double now, float *mx, float *my);

} // namespace
2 changes: 1 addition & 1 deletion UI/NativeApp.cpp
Expand Up @@ -1329,7 +1329,7 @@ void NativeMouseDelta(float dx, float dy) {
if (!g_Config.bMouseControl)
return;

MouseEventProcessor::ProcessDelta(dx, dy);
MouseEventProcessor::ProcessDelta(time_now_d(), dx, dy);
}

// Called from NativeFrame.
Expand Down
2 changes: 1 addition & 1 deletion Windows/WindowsHost.cpp
Expand Up @@ -77,7 +77,7 @@ void WindowsInputManager::Init() {
}

void WindowsInputManager::PollControllers() {
static const int CHECK_FREQUENCY = 71;
static const int CHECK_FREQUENCY = 71; // Just an arbitrary prime to try to not collide with other periodic checks.
if (checkCounter_++ > CHECK_FREQUENCY) {
#ifndef _M_ARM
size_t newCount = DinputDevice::getNumPads();
Expand Down

0 comments on commit d397635

Please sign in to comment.