Skip to content

Commit

Permalink
Merge pull request #18403 from hrydgard/tilt-fixes
Browse files Browse the repository at this point in the history
Fixes for tilt control bugs
  • Loading branch information
hrydgard committed Nov 9, 2023
2 parents 5a72e2d + 4f2f1c4 commit 2036f1c
Show file tree
Hide file tree
Showing 12 changed files with 49 additions and 23 deletions.
23 changes: 8 additions & 15 deletions Common/Data/Format/IniFile.cpp
Expand Up @@ -7,6 +7,7 @@

#include <inttypes.h>

// Hm, what's this for?
#ifndef _MSC_VER
#include <strings.h>
#endif
Expand All @@ -19,23 +20,14 @@
#include <vector>

#include "Common/Data/Format/IniFile.h"
#include "Common/Data/Text/Parsers.h"
#include "Common/File/VFS/VFS.h"
#include "Common/File/FileUtil.h"
#include "Common/Data/Text/Parsers.h"

#ifdef _WIN32
#include "Common/Data/Encoding/Utf8.h"
#endif
#include "Common/Log.h"
#include "Common/Math/math_util.h"

#include "Common/StringUtils.h"

bool StringViewEqualCaseInsensitive(const std::string_view lhs, const std::string_view rhs) {
if (lhs.size() != rhs.size()) {
return false;
}
return ::strncasecmp(lhs.data(), rhs.data(), rhs.size()) == 0;
}

// This unescapes # signs.
// NOTE: These parse functions can make better use of the string_view - the pos argument should not be needed, for example.
static bool ParseLineKey(std::string_view line, size_t &pos, std::string *keyOut) {
Expand Down Expand Up @@ -199,15 +191,15 @@ void Section::Clear() {

ParsedIniLine *Section::GetLine(const char *key) {
for (auto &line : lines_) {
if (StringViewEqualCaseInsensitive(line.Key(), key))
if (equalsNoCase(line.Key(), key))
return &line;
}
return nullptr;
}

const ParsedIniLine *Section::GetLine(const char* key) const {
for (auto &line : lines_) {
if (StringViewEqualCaseInsensitive(line.Key(), key))
if (equalsNoCase(line.Key(), key))
return &line;
}
return nullptr;
Expand All @@ -222,6 +214,7 @@ void Section::Set(const char* key, uint64_t newValue) {
}

void Section::Set(const char* key, float newValue) {
_dbg_assert_(!my_isnanorinf(newValue));
Set(key, StringFromFormat("%f", newValue).c_str());
}

Expand Down Expand Up @@ -397,7 +390,7 @@ bool Section::Get(const char* key, double* value, double defaultValue) const

bool Section::Exists(const char *key) const {
for (auto &line : lines_) {
if (StringViewEqualCaseInsensitive(key, line.Key()))
if (equalsNoCase(key, line.Key()))
return true;
}
return false;
Expand Down
1 change: 1 addition & 0 deletions Common/System/System.h
Expand Up @@ -130,6 +130,7 @@ enum SystemProperty {
SYSPROP_HAS_IMAGE_BROWSER,
SYSPROP_HAS_BACK_BUTTON,
SYSPROP_HAS_KEYBOARD,
SYSPROP_HAS_ACCELEROMETER, // Used to enable/disable tilt input settings
SYSPROP_HAS_OPEN_DIRECTORY,
SYSPROP_HAS_LOGIN_DIALOG,
SYSPROP_HAS_TEXT_INPUT_DIALOG, // Indicates that System_InputBoxGetString is available.
Expand Down
3 changes: 3 additions & 0 deletions Common/UI/PopupScreens.cpp
Expand Up @@ -167,12 +167,15 @@ PopupSliderChoice::PopupSliderChoice(int *value, int minValue, int maxValue, int

PopupSliderChoiceFloat::PopupSliderChoiceFloat(float *value, float minValue, float maxValue, float defaultValue, const std::string &text, ScreenManager *screenManager, const std::string &units, LayoutParams *layoutParams)
: AbstractChoiceWithValueDisplay(text, layoutParams), value_(value), minValue_(minValue), maxValue_(maxValue), defaultValue_(defaultValue), step_(1.0f), units_(units), screenManager_(screenManager) {
_dbg_assert_(maxValue > minValue);
fmt_ = "%2.2f";
OnClick.Handle(this, &PopupSliderChoiceFloat::HandleClick);
}

PopupSliderChoiceFloat::PopupSliderChoiceFloat(float *value, float minValue, float maxValue, float defaultValue, const std::string &text, float step, ScreenManager *screenManager, const std::string &units, LayoutParams *layoutParams)
: AbstractChoiceWithValueDisplay(text, layoutParams), value_(value), minValue_(minValue), maxValue_(maxValue), defaultValue_(defaultValue), step_(step), units_(units), screenManager_(screenManager) {
_dbg_assert_(step > 0.0f);
_dbg_assert_(maxValue > minValue);
fmt_ = "%2.2f";
OnClick.Handle(this, &PopupSliderChoiceFloat::HandleClick);
}
Expand Down
4 changes: 4 additions & 0 deletions Common/UI/View.cpp
Expand Up @@ -1557,6 +1557,9 @@ bool SliderFloat::ApplyKey(InputKeyCode keyCode) {
default:
return false;
}

_dbg_assert_(!my_isnanorinf(*value_));

EventParams params{};
params.v = this;
params.a = (uint32_t)(*value_);
Expand Down Expand Up @@ -1584,6 +1587,7 @@ bool SliderFloat::Touch(const TouchInput &input) {
}

void SliderFloat::Clamp() {
_dbg_assert_(!my_isnanorinf(*value_));
if (*value_ < minValue_)
*value_ = minValue_;
else if (*value_ > maxValue_)
Expand Down
19 changes: 17 additions & 2 deletions Core/TiltEventProcessor.cpp
Expand Up @@ -35,8 +35,11 @@ void GenerateTriggerButtonEvent(int digitalX, int digitalY);
// deadzone is normalized - 0 to 1
// sensitivity controls how fast the deadzone reaches max value
inline float ApplyDeadzone(float x, float deadzone) {
if (deadzone >= 0.99f) {
// Meaningless, and not reachable with normal controls.
return x;
}
const float factor = 1.0f / (1.0f - deadzone);

if (x > deadzone) {
return (x - deadzone) * factor + deadzone;
} else if (x < -deadzone) {
Expand All @@ -55,7 +58,9 @@ inline void ApplyInverseDeadzone(float x, float y, float *outX, float *outY, flo
}
if (circular) {
float magnitude = sqrtf(x * x + y * y);
magnitude = (magnitude + inverseDeadzone) / magnitude;
if (magnitude > 0.00001f) {
magnitude = (magnitude + inverseDeadzone) / magnitude;
}
*outX = Clamp(x * magnitude, -1.0f, 1.0f);
*outY = Clamp(y * magnitude, -1.0f, 1.0f);
} else {
Expand Down Expand Up @@ -83,6 +88,10 @@ void ProcessTilt(bool landscape, float calibrationAngle, float x, float y, float
float yAngle = angleAroundX - calibrationAngle;
float xAngle = asinf(down.x);

_dbg_assert_(!my_isnanorinf(angleAroundX));
_dbg_assert_(!my_isnanorinf(yAngle));
_dbg_assert_(!my_isnanorinf(xAngle));

float tiltX = xAngle;
float tiltY = yAngle;

Expand All @@ -107,11 +116,17 @@ void ProcessTilt(bool landscape, float calibrationAngle, float x, float y, float
float adjustedTiltX = ApplyDeadzone(tiltX, g_Config.fTiltAnalogDeadzoneRadius);
float adjustedTiltY = ApplyDeadzone(tiltY, g_Config.fTiltAnalogDeadzoneRadius);

_dbg_assert_(!my_isnanorinf(adjustedTiltX));
_dbg_assert_(!my_isnanorinf(adjustedTiltY));

// Unlike regular deadzone, where per-axis is okay, inverse deadzone (to compensate for game deadzones) really needs to be
// applied on the two axes together.
// TODO: Share this code with the joystick code. For now though, we keep it separate.
ApplyInverseDeadzone(adjustedTiltX, adjustedTiltY, &adjustedTiltX, &adjustedTiltY, g_Config.fTiltInverseDeadzone, g_Config.bTiltCircularInverseDeadzone);

_dbg_assert_(!my_isnanorinf(adjustedTiltX));
_dbg_assert_(!my_isnanorinf(adjustedTiltY));

rawTiltAnalogX = adjustedTiltX;
rawTiltAnalogY = adjustedTiltY;
GenerateAnalogStickEvent(adjustedTiltX, adjustedTiltY);
Expand Down
2 changes: 0 additions & 2 deletions GPU/Common/GPUStateUtils.h
Expand Up @@ -249,8 +249,6 @@ struct GenericLogicState {
// Same logicOp is kept.
}
}

void Log();
};

struct ComputedPipelineState {
Expand Down
6 changes: 6 additions & 0 deletions SDL/SDLMain.cpp
Expand Up @@ -584,6 +584,12 @@ bool System_GetPropertyBool(SystemProperty prop) {
case SYSPROP_HAS_FOLDER_BROWSER:
case SYSPROP_HAS_FILE_BROWSER:
return true;
#endif
case SYSPROP_HAS_ACCELEROMETER:
#if defined(MOBILE_DEVICE)
return true;
#else
return false;
#endif
default:
return false;
Expand Down
4 changes: 2 additions & 2 deletions UI/GameSettingsScreen.cpp
Expand Up @@ -643,10 +643,10 @@ void GameSettingsScreen::CreateControlsSettings(UI::ViewGroup *controlsSettings)
controlsSettings->Add(new CheckBox(&g_Config.bGamepadOnlyFocused, co->T("Ignore gamepads when not focused")));
#endif

if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_MOBILE) {
if (System_GetPropertyBool(SYSPROP_HAS_ACCELEROMETER)) {
Choice *customizeTilt = controlsSettings->Add(new Choice(co->T("Tilt control setup")));
customizeTilt->OnClick.Handle(this, &GameSettingsScreen::OnTiltCustomize);
} else if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_VR) {
} else if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_VR) { // TODO: This seems like a regression
controlsSettings->Add(new CheckBox(&g_Config.bHapticFeedback, co->T("HapticFeedback", "Haptic Feedback (vibration)")));
}

Expand Down
4 changes: 2 additions & 2 deletions UI/TiltAnalogSettingsScreen.cpp
Expand Up @@ -122,8 +122,8 @@ void TiltAnalogSettingsScreen::CreateViews() {

settings->Add(new ItemHeader(co->T("Sensitivity")));
if (g_Config.iTiltInputType == 1) {
settings->Add(new PopupSliderChoiceFloat(&g_Config.fTiltAnalogDeadzoneRadius, 0.0f, 0.8f, 0.0f, co->T("Deadzone radius"), 0.01f, screenManager(), "/ 1.0"))->SetEnabledFunc(enabledFunc);
settings->Add(new PopupSliderChoiceFloat(&g_Config.fTiltInverseDeadzone, 0.0f, 0.8f, 0.0f, co->T("Low end radius"), 0.0f, screenManager(), "/ 1.0"))->SetEnabledFunc(enabledFunc);
settings->Add(new PopupSliderChoiceFloat(&g_Config.fTiltAnalogDeadzoneRadius, 0.0f, 0.8f, 0.0f, co->T("Deadzone radius"), 0.02f, screenManager(), "/ 1.0"))->SetEnabledFunc(enabledFunc);
settings->Add(new PopupSliderChoiceFloat(&g_Config.fTiltInverseDeadzone, 0.0f, 0.8f, 0.0f, co->T("Low end radius"), 0.02f, screenManager(), "/ 1.0"))->SetEnabledFunc(enabledFunc);
settings->Add(new CheckBox(&g_Config.bTiltCircularInverseDeadzone, co->T("Circular low end radius")))->SetEnabledFunc(enabledFunc);
}
settings->Add(new PopupSliderChoice(&g_Config.iTiltSensitivityX, 0, 100, 60, co->T("Tilt Sensitivity along X axis"), screenManager(), "%"))->SetEnabledFunc(enabledFunc);
Expand Down
2 changes: 2 additions & 0 deletions UWP/PPSSPP_UWPMain.cpp
Expand Up @@ -416,6 +416,8 @@ bool System_GetPropertyBool(SystemProperty prop) {
return true; // we just use the file browser
case SYSPROP_HAS_BACK_BUTTON:
return true;
case SYSPROP_HAS_ACCELEROMETER:
return IsMobile();
case SYSPROP_APP_GOLD:
#ifdef GOLD
return true;
Expand Down
2 changes: 2 additions & 0 deletions android/jni/app-android.cpp
Expand Up @@ -530,6 +530,8 @@ bool System_GetPropertyBool(SystemProperty prop) {
}
case SYSPROP_HAS_KEYBOARD:
return deviceType != DEVICE_TYPE_VR;
case SYSPROP_HAS_ACCELEROMETER:
return deviceType == DEVICE_TYPE_MOBILE;
#ifndef HTTPS_NOT_AVAILABLE
case SYSPROP_SUPPORTS_HTTPS:
return !g_Config.bDisableHTTPS;
Expand Down
2 changes: 2 additions & 0 deletions ios/main.mm
Expand Up @@ -160,6 +160,8 @@ bool System_GetPropertyBool(SystemProperty prop) {
return false;
case SYSPROP_HAS_BACK_BUTTON:
return false;
case SYSPROP_HAS_ACCELEROMETER:
return true;
case SYSPROP_APP_GOLD:
#ifdef GOLD
return true;
Expand Down

0 comments on commit 2036f1c

Please sign in to comment.