Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace the "Test Analogs" screen with a new screen that lets you directly try the settings. #14596

Merged
merged 7 commits into from
Jul 9, 2021
Next Next commit
Replace the "Test Analogs" screen with a new screen that lets you dir…
…ectly try the settings.
  • Loading branch information
hrydgard committed Jul 9, 2021
commit 2303926e88cb88cef85301e4e346bd53150f3e86
11 changes: 10 additions & 1 deletion Core/ControlMapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ static float MapAxisValue(float v) {
return sign * Clamp(invDeadzone + (abs(v) - deadzone) / (1.0f - deadzone) * (sensitivity - invDeadzone), 0.0f, 1.0f);
}

static void ConvertAnalogStick(float &x, float &y) {
void ConvertAnalogStick(float &x, float &y) {
const bool isCircular = g_Config.bAnalogIsCircular;

float norm = std::max(fabsf(x), fabsf(y));
Expand All @@ -40,6 +40,11 @@ void ControlMapper::SetCallbacks(std::function<void(int)> onVKeyDown, std::funct
setPSPAnalog_ = setPSPAnalog;
}

void ControlMapper::SetRawCallback(std::function<void(int, float, float)> setRawAnalog) {
setRawAnalog_ = setRawAnalog;
}


void ControlMapper::SetPSPAxis(char axis, float value, int stick) {
static float history[2][2] = {};

Expand All @@ -50,6 +55,10 @@ void ControlMapper::SetPSPAxis(char axis, float value, int stick) {
float x = history[stick][0];
float y = history[stick][1];

if (setRawAnalog_) {
setRawAnalog_(stick, x, y);
}

ConvertAnalogStick(x, y);

setPSPAnalog_(stick, x, y);
Expand Down
7 changes: 7 additions & 0 deletions Core/ControlMapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ class ControlMapper {
bool Key(const KeyInput &key, bool *pauseTrigger);
bool Axis(const AxisInput &axis);

// Required callbacks
void SetCallbacks(
std::function<void(int)> onVKeyDown,
std::function<void(int)> onVKeyUp,
std::function<void(int, float, float)> setPSPAnalog);

// Optional callback, only used in config
void SetRawCallback(std::function<void(int, float, float)> setRawAnalog);

private:
void processAxis(const AxisInput &axis, int direction);
void pspKey(int pspKeyCode, int flags);
Expand All @@ -41,4 +45,7 @@ class ControlMapper {
std::function<void(int)> onVKeyDown_;
std::function<void(int)> onVKeyUp_;
std::function<void(int, float, float)> setPSPAnalog_;
std::function<void(int, float, float)> setRawAnalog_;
};

void ConvertAnalogStick(float &x, float &y);
160 changes: 88 additions & 72 deletions UI/ControlMappingScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ void ControlMappingScreen::CreateViews() {
if (!KeyMap::HasBuiltinController(sysName) && KeyMap::GetSeenPads().size()) {
leftColumn->Add(new Choice(km->T("Autoconfigure")))->OnClick.Handle(this, &ControlMappingScreen::OnAutoConfigure);
}
leftColumn->Add(new Choice(km->T("Test Analogs")))->OnClick.Handle(this, &ControlMappingScreen::OnTestAnalogs);

leftColumn->Add(new Spacer(new LinearLayoutParams(1.0f)));
AddStandardBack(leftColumn);

Expand Down Expand Up @@ -283,11 +283,6 @@ UI::EventReturn ControlMappingScreen::OnAutoConfigure(UI::EventParams &params) {
return UI::EVENT_DONE;
}

UI::EventReturn ControlMappingScreen::OnTestAnalogs(UI::EventParams &params) {
screenManager()->push(new AnalogTestScreen());
return UI::EVENT_DONE;
}

void ControlMappingScreen::dialogFinished(const Screen *dialog, DialogResult result) {
if (result == DR_OK && dialog->tag() == "listpopup") {
ListPopupScreen *popup = (ListPopupScreen *)dialog;
Expand Down Expand Up @@ -430,20 +425,14 @@ bool KeyMappingNewMouseKeyDialog::axis(const AxisInput &axis) {

class JoystickHistoryView : public UI::InertView {
public:
JoystickHistoryView(int xAxis, int xDevice, int xDir, int yAxis, int yDevice, int yDir, UI::LayoutParams *layoutParams = nullptr)
: UI::InertView(layoutParams),
xAxis_(xAxis), xDir_(xDir),
yAxis_(yAxis), yDir_(yDir) {}
JoystickHistoryView(std::string title, UI::LayoutParams *layoutParams = nullptr)
: UI::InertView(layoutParams), title_(title) {}
void Draw(UIContext &dc) override;
std::string DescribeText() const override { return ""; }
std::string DescribeText() const override { return "Analog Stick View"; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has a title_, so any description should include the title, and possibly values. I was trying to use this semantically as an accessibility tree. Using it as a developer name for the control is more the purpose of DescribeLog().

I'd previously intentionally made it blank because the associated text was separate from this graphical representation, so this view had on separate and useful textual meaning. Not sure if that's still true.

I realize it's not really exposed in a useful way to any accessibility tree at this point, and you probably wouldn't search it, but just wanted to explain the purpose of the method as I'd considered it.

-[Unknown]

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right, this was just a driveby change and I didn't reflect on the real purpose. Thanks for clarifying!

void Update() override;
void Axis(const AxisInput &input) override {
// TODO: Check input.deviceId?
if (input.axisId == xAxis_) {
curX_ = input.value * xDir_;
} else if (input.axisId == yAxis_) {
curY_ = input.value * yDir_;
}
void SetXY(float x, float y) {
curX_ = x;
curY_ = y;
}

private:
Expand All @@ -452,58 +441,55 @@ class JoystickHistoryView : public UI::InertView {
float y;
};

int xAxis_;
int xDir_;
int yAxis_;
int yDir_;

float curX_ = 0.0f;
float curY_ = 0.0f;

std::deque<Location> locations_;
int maxCount_ = 500;
std::string title_;
};

void JoystickHistoryView::Draw(UIContext &dc) {
if (xAxis_ > -1 && yAxis_ > -1) {
const AtlasImage *image = dc.Draw()->GetAtlas()->getImage(ImageID("I_CROSS"));
if (!image) {
return;
const AtlasImage *image = dc.Draw()->GetAtlas()->getImage(ImageID("I_CROSS"));
if (!image) {
return;
}
float minRadius = std::min(bounds_.w, bounds_.h) * 0.5f - image->w;
dc.Begin();
dc.DrawTextShadow(title_.c_str(), bounds_.centerX(), bounds_.y2(), 0xFFFFFFFF, ALIGN_BOTTOM | ALIGN_HCENTER);
dc.Flush();
dc.BeginNoTex();
dc.Draw()->RectOutline(bounds_.centerX() - minRadius, bounds_.centerY() - minRadius, minRadius * 2.0f, minRadius * 2.0f, 0x80FFFFFF);
dc.Flush();
dc.Begin();
int a = maxCount_ - (int)locations_.size();
for (auto iter = locations_.begin(); iter != locations_.end(); ++iter) {
float x = bounds_.centerX() + minRadius * iter->x;
float y = bounds_.centerY() - minRadius * iter->y;
float alpha = (float)a / (float)(maxCount_ - 1);
if (alpha < 0.0f) {
alpha = 0.0f;
}
float minRadius = std::min(bounds_.w, bounds_.h) * 0.5f - image->w;
dc.BeginNoTex();
dc.Draw()->RectOutline(bounds_.centerX() - minRadius, bounds_.centerY() - minRadius, minRadius * 2.0f, minRadius * 2.0f, 0x80FFFFFF);
dc.Flush();
dc.Begin();
int a = maxCount_ - (int)locations_.size();
for (auto iter = locations_.begin(); iter != locations_.end(); ++iter) {
float x = bounds_.centerX() + minRadius * iter->x;
float y = bounds_.centerY() - minRadius * iter->y;
float alpha = (float)a / maxCount_;
if (alpha < 0.0f) {
alpha = 0.0f;
}
dc.Draw()->DrawImage(ImageID("I_CROSS"), x, y, 0.8f, colorAlpha(0xFFFFFF, alpha), ALIGN_CENTER);
a++;
// Emphasize the newest (higher) ones.
alpha = powf(alpha, 3.7f);
if (alpha >= 1.0f) {
dc.Draw()->DrawImage(ImageID("I_CIRCLE"), x, y, 1.0f, colorAlpha(0xFFFFFF, 1.0), ALIGN_CENTER);
} else {
dc.Draw()->DrawImage(ImageID("I_CIRCLE"), x, y, 0.8f, colorAlpha(0xC0C0C0, alpha * 0.5f), ALIGN_CENTER);
}
dc.Flush();
} else {
dc.Begin();
dc.DrawText("N/A", bounds_.centerX(), bounds_.centerY(), 0xFFFFFFFF, ALIGN_CENTER);
dc.Flush();
a++;
}
dc.Flush();
}

void JoystickHistoryView::Update() {
if (xAxis_ > -1 && yAxis_ > -1) {
locations_.push_back(Location{ curX_, curY_ });
if ((int)locations_.size() > maxCount_) {
locations_.pop_front();
}
locations_.push_back(Location{ curX_, curY_ });
if ((int)locations_.size() > maxCount_) {
locations_.pop_front();
}
}

bool AnalogTestScreen::key(const KeyInput &key) {
bool AnalogSetupScreen::key(const KeyInput &key) {
bool retval = true;
if (UI::IsEscapeKey(key)) {
TriggerFinish(DR_BACK);
Expand All @@ -523,8 +509,13 @@ bool AnalogTestScreen::key(const KeyInput &key) {
return retval;
}

bool AnalogTestScreen::axis(const AxisInput &axis) {
UIScreen::axis(axis);
bool AnalogSetupScreen::axis(const AxisInput &axis) {
// We DON'T call UIScreen::Axis here! Otherwise it'll try to move the UI focus around.
// UIScreen::axis(axis);

// Instead we just send the input directly to the mapper, that we'll visualize.
mapper_.Axis(axis);

// This is mainly to catch axis events that would otherwise get translated
// into arrow keys, since seeing keyboard arrow key events appear when using
// a controller would be confusing for the user.
Expand All @@ -546,35 +537,60 @@ bool AnalogTestScreen::axis(const AxisInput &axis) {
return false;
}

void AnalogTestScreen::CreateViews() {
AnalogSetupScreen::AnalogSetupScreen() {
mapper_.SetCallbacks([](int vkey) {}, [](int vkey) {}, [&](int stick, float x, float y) {
analogX_[stick] = x;
analogY_[stick] = y;
});
mapper_.SetRawCallback([&](int stick, float x, float y) {
rawX_[stick] = x;
rawY_[stick] = y;
});
}

void AnalogSetupScreen::CreateViews() {
using namespace UI;

auto di = GetI18NCategory("Dialog");

root_ = new LinearLayout(ORIENT_VERTICAL);

LinearLayout *theTwo = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(1.0f));
root_ = new LinearLayout(ORIENT_HORIZONTAL);

int axis1, device1, dir1;
int axis2, device2, dir2;
LinearLayout *leftColumn = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(300.0f, FILL_PARENT)));
LinearLayout *rightColumn = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));

if (!KeyMap::AxisFromPspButton(VIRTKEY_AXIS_X_MAX, &device1, &axis1, &dir1)) axis1 = -1;
if (!KeyMap::AxisFromPspButton(VIRTKEY_AXIS_Y_MAX, &device2, &axis2, &dir2)) axis2 = -1;
auto co = GetI18NCategory("Controls");
leftColumn->Add(new ItemHeader(co->T("Analog Settings", "Analog Settings")));
leftColumn->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogDeadzone, 0.0f, 1.0f, co->T("Deadzone Radius"), 0.01f, screenManager(), "/ 1.0"));
leftColumn->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogInverseDeadzone, 0.0f, 1.0f, co->T("Analog Mapper Low End", "Analog Mapper Low End (Inverse Deadzone)"), 0.01f, screenManager(), "/ 1.0"));
leftColumn->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogSensitivity, 0.0f, 10.0f, co->T("Analog Mapper High End", "Analog Mapper High End (Axis Sensitivity)"), 0.01f, screenManager(), "x"));
leftColumn->Add(new CheckBox(&g_Config.bAnalogIsCircular, co->T("Circular Analog Stick Input")));
leftColumn->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogAutoRotSpeed, 0.0f, 25.0f, co->T("Analog auto-rotation speed"), 1.0f, screenManager()));

theTwo->Add(new JoystickHistoryView(axis1, device1, dir1, axis2, device2, dir2, new LinearLayoutParams(1.0f)));
LinearLayout *theTwo = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(1.0f));

if (!KeyMap::AxisFromPspButton(VIRTKEY_AXIS_RIGHT_X_MAX, &device1, &axis1, &dir1)) axis1 = -1;
if (!KeyMap::AxisFromPspButton(VIRTKEY_AXIS_RIGHT_Y_MAX, &device2, &axis2, &dir2)) axis2 = -1;
stickView_[0] = theTwo->Add(new JoystickHistoryView(co->T("Raw Stick Input"), new LinearLayoutParams(1.0f)));
stickView_[1] = theTwo->Add(new JoystickHistoryView(co->T("Emulated PSP Input"), new LinearLayoutParams(1.0f)));

theTwo->Add(new JoystickHistoryView(axis1, device1, dir1, axis2, device2, dir2, new LinearLayoutParams(1.0f)));
rightColumn->Add(theTwo);

root_->Add(theTwo);

lastLastKeyEvent_ = root_->Add(new TextView("-", new LayoutParams(FILL_PARENT, WRAP_CONTENT)));
lastLastKeyEvent_ = rightColumn->Add(new TextView("-", new LayoutParams(FILL_PARENT, WRAP_CONTENT)));
lastLastKeyEvent_->SetTextColor(0x80FFFFFF); // semi-transparent
lastKeyEvent_ = root_->Add(new TextView("-", new LayoutParams(FILL_PARENT, WRAP_CONTENT)));
lastKeyEvent_ = rightColumn->Add(new TextView("-", new LayoutParams(FILL_PARENT, WRAP_CONTENT)));

root_->Add(new Button(di->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
leftColumn->Add(new Spacer(new LinearLayoutParams(1.0)));
leftColumn->Add(new Button(di->T("Back"), new LayoutParams(FILL_PARENT, WRAP_CONTENT)))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
}

void AnalogSetupScreen::update() {
// We ignore the secondary stick for now and just use the two views
// for raw and psp input.
if (stickView_[0]) {
stickView_[0]->SetXY(rawX_[0], rawY_[0]);
}
if (stickView_[1]) {
stickView_[1]->SetXY(analogX_[0], analogY_[0]);
}
UIScreen::update();
}

bool TouchTestScreen::touch(const TouchInput &touch) {
Expand Down
21 changes: 18 additions & 3 deletions UI/ControlMappingScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@

#include "Common/UI/View.h"
#include "Common/UI/UIScreen.h"

#include "Common/Data/Text/I18n.h"

#include "Core/ControlMapper.h"

#include "UI/MiscScreens.h"

class SingleControlMapper;
Expand Down Expand Up @@ -96,16 +98,29 @@ class KeyMappingNewMouseKeyDialog : public PopupScreen {
bool mapped_; // Prevent double registrations
};

class AnalogTestScreen : public UIDialogScreenWithBackground {
class JoystickHistoryView;

class AnalogSetupScreen : public UIDialogScreenWithBackground {
public:
AnalogTestScreen() {}
AnalogSetupScreen();

bool key(const KeyInput &key) override;
bool axis(const AxisInput &axis) override;

void update() override;

protected:
virtual void CreateViews() override;

ControlMapper mapper_;

float analogX_[2]{};
float analogY_[2]{};
float rawX_[2]{};
float rawY_[2]{};

JoystickHistoryView *stickView_[2];

UI::TextView *lastKeyEvent_ = nullptr;
UI::TextView *lastLastKeyEvent_ = nullptr;
};
Expand Down
13 changes: 6 additions & 7 deletions UI/GameSettingsScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -727,13 +727,7 @@ void GameSettingsScreen::CreateViews() {
style->SetEnabledPtr(&g_Config.bShowTouchControls);
}

controlsSettings->Add(new ItemHeader(co->T("Analog Settings", "Analog Settings")));
controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogDeadzone, 0.0f, 1.0f, co->T("Deadzone Radius"), 0.01f, screenManager(), "/ 1.0"));
controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogInverseDeadzone, 0.0f, 1.0f, co->T("Analog Mapper Low End", "Analog Mapper Low End (Inverse Deadzone)"), 0.01f, screenManager(), "/ 1.0"));
controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogSensitivity, 0.0f, 10.0f, co->T("Analog Mapper High End", "Analog Mapper High End (Axis Sensitivity)"), 0.01f, screenManager(), "x"));
controlsSettings->Add(new CheckBox(&g_Config.bAnalogIsCircular, co->T("Circular Analog Stick Input")));

controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogAutoRotSpeed, 0.0f, 25.0f, co->T("Analog auto-rotation speed"), 1.0f, screenManager()));
controlsSettings->Add(new Choice(co->T("Calibrate Analog Sticks")))->OnClick.Handle(this, &GameSettingsScreen::OnCalibrateAnalogs);

controlsSettings->Add(new ItemHeader(co->T("Keyboard", "Keyboard Control Settings")));
#if defined(USING_WIN_UI)
Expand Down Expand Up @@ -1543,6 +1537,11 @@ UI::EventReturn GameSettingsScreen::OnControlMapping(UI::EventParams &e) {
return UI::EVENT_DONE;
}

UI::EventReturn GameSettingsScreen::OnCalibrateAnalogs(UI::EventParams &e) {
screenManager()->push(new AnalogSetupScreen());
return UI::EVENT_DONE;
}

UI::EventReturn GameSettingsScreen::OnTouchControlLayout(UI::EventParams &e) {
screenManager()->push(new TouchControlLayoutScreen());
return UI::EVENT_DONE;
Expand Down
1 change: 1 addition & 0 deletions UI/GameSettingsScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class GameSettingsScreen : public UIDialogScreenWithGameBackground {

// Event handlers
UI::EventReturn OnControlMapping(UI::EventParams &e);
UI::EventReturn OnCalibrateAnalogs(UI::EventParams &e);
UI::EventReturn OnTouchControlLayout(UI::EventParams &e);
UI::EventReturn OnDumpNextFrameToLog(UI::EventParams &e);
UI::EventReturn OnTiltTypeChange(UI::EventParams &e);
Expand Down