From 77c85bccddddad60fbaa90bf0492d671dd7234ae Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sun, 8 Jun 2014 15:38:13 +0200 Subject: [PATCH] Don't lose focus after mapping a control. Makes it a lot less aggravating to remap more than one control using a controller. Also fixes a race condition. --- UI/ControlMappingScreen.cpp | 41 +++++++++++++++++++++++++++++-------- UI/ControlMappingScreen.h | 11 ++++++++-- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index fb61009096..cc20a00e13 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -35,10 +35,10 @@ class ControlMapper : public UI::LinearLayout { public: - ControlMapper(int pspKey, std::string keyName, ScreenManager *scrm, UI::LinearLayoutParams *layoutParams = 0); + ControlMapper(ControlMappingScreen *ctrlScreen, int pspKey, std::string keyName, ScreenManager *scrm, UI::LinearLayoutParams *layoutParams = 0); virtual void Update(const InputState &input); - + int GetPspKey() const { return pspKey_; } private: void Refresh(); @@ -56,6 +56,7 @@ private: ADD, }; + ControlMappingScreen *ctrlScreen_; Action action_; int actionIndex_; int pspKey_; @@ -64,8 +65,8 @@ private: bool refresh_; }; -ControlMapper::ControlMapper(int pspKey, std::string keyName, ScreenManager *scrm, UI::LinearLayoutParams *layoutParams) - : UI::LinearLayout(UI::ORIENT_VERTICAL, layoutParams), action_(NONE), pspKey_(pspKey), keyName_(keyName), scrm_(scrm), refresh_(false) { +ControlMapper::ControlMapper(ControlMappingScreen *ctrlScreen, int pspKey, std::string keyName, ScreenManager *scrm, UI::LinearLayoutParams *layoutParams) + : UI::LinearLayout(UI::ORIENT_VERTICAL, layoutParams), ctrlScreen_(ctrlScreen), action_(NONE), pspKey_(pspKey), keyName_(keyName), scrm_(scrm), refresh_(false) { Refresh(); } @@ -77,6 +78,7 @@ void ControlMapper::Update(const InputState &input) { } void ControlMapper::Refresh() { + bool hasFocus = UI::GetFocusedView() == this; Clear(); I18NCategory *mc = GetI18NCategory("MappableControls"); @@ -143,6 +145,9 @@ void ControlMapper::Refresh() { Choice *c = rightColumn->Add(new Choice("", new LinearLayoutParams(FILL_PARENT, itemH))); c->OnClick.Handle(this, &ControlMapper::OnAdd); } + + if (hasFocus) + this->SetFocus(); } void ControlMapper::MappedCallback(KeyDef kdf) { @@ -160,6 +165,8 @@ void ControlMapper::MappedCallback(KeyDef kdf) { ; } refresh_ = true; + ctrlScreen_->KeyMapped(pspKey_); + // After this, we do not exist any more. So the refresh_ = true is probably irrelevant. } UI::EventReturn ControlMapper::OnReplace(UI::EventParams ¶ms) { @@ -190,6 +197,7 @@ UI::EventReturn ControlMapper::OnDelete(UI::EventParams ¶ms) { void ControlMappingScreen::CreateViews() { using namespace UI; + mappers_.clear(); I18NCategory *k = GetI18NCategory("KeyMapping"); I18NCategory *d = GetI18NCategory("Dialog"); @@ -205,17 +213,18 @@ void ControlMappingScreen::CreateViews() { leftColumn->Add(new Spacer(new LinearLayoutParams(1.0f))); leftColumn->Add(new Choice(d->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); - ScrollView *rightScroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)); - rightScroll->SetScrollToTop(false); + rightScroll_ = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)); + rightScroll_->SetScrollToTop(false); LinearLayout *rightColumn = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)); - rightScroll->Add(rightColumn); + rightScroll_->Add(rightColumn); root_->Add(leftColumn); - root_->Add(rightScroll); + root_->Add(rightScroll_); std::vector mappableKeys = KeyMap::GetMappableKeys(); for (size_t i = 0; i < mappableKeys.size(); i++) { - rightColumn->Add(new ControlMapper(mappableKeys[i].key, mappableKeys[i].name, screenManager(), new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); + ControlMapper *mapper = rightColumn->Add(new ControlMapper(this, mappableKeys[i].key, mappableKeys[i].name, screenManager(), new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); + mappers_.push_back(mapper); } } @@ -261,6 +270,13 @@ void ControlMappingScreen::dialogFinished(const Screen *dialog, DialogResult res } } +void ControlMappingScreen::KeyMapped(int pspkey) { // Notification to let us refocus the same one after recreating views. + for (int i = 0; i < mappers_.size(); i++) { + if (mappers_[i]->GetPspKey() == pspkey) + SetFocusedView(mappers_[i]); + } +} + void KeyMappingNewKeyDialog::CreatePopupContents(UI::ViewGroup *parent) { using namespace UI; @@ -272,11 +288,14 @@ void KeyMappingNewKeyDialog::CreatePopupContents(UI::ViewGroup *parent) { } void KeyMappingNewKeyDialog::key(const KeyInput &key) { + if (mapped_) + return; if (key.flags & KEY_DOWN) { if (key.keyCode == NKCODE_EXT_MOUSEBUTTON_1) { return; } + mapped_ = true; KeyDef kdf(key.deviceId, key.keyCode); screenManager()->finishDialog(this, DR_OK); if (callback_) @@ -285,6 +304,8 @@ void KeyMappingNewKeyDialog::key(const KeyInput &key) { } void KeyMappingNewKeyDialog::axis(const AxisInput &axis) { + if (mapped_) + return; switch (axis.axisId) { // Ignore the accelerometer for mapping for now. case JOYSTICK_AXIS_ACCELEROMETER_X: @@ -304,6 +325,7 @@ void KeyMappingNewKeyDialog::axis(const AxisInput &axis) { } if (axis.value > AXIS_BIND_THRESHOLD) { + mapped_ = true; KeyDef kdf(axis.deviceId, KeyMap::TranslateKeyCodeFromAxis(axis.axisId, 1)); screenManager()->finishDialog(this, DR_OK); if (callback_) @@ -311,6 +333,7 @@ void KeyMappingNewKeyDialog::axis(const AxisInput &axis) { } if (axis.value < -AXIS_BIND_THRESHOLD) { + mapped_ = true; KeyDef kdf(axis.deviceId, KeyMap::TranslateKeyCodeFromAxis(axis.axisId, -1)); screenManager()->finishDialog(this, DR_OK); if (callback_) diff --git a/UI/ControlMappingScreen.h b/UI/ControlMappingScreen.h index f9ed2e9262..f1dfa70514 100644 --- a/UI/ControlMappingScreen.h +++ b/UI/ControlMappingScreen.h @@ -17,31 +17,37 @@ #pragma once +#include #include "base/functional.h" #include "ui/view.h" #include "ui/ui_screen.h" #include "UI/MiscScreens.h" +class ControlMapper; + class ControlMappingScreen : public UIDialogScreenWithBackground { public: ControlMappingScreen() {} + void KeyMapped(int pspkey); // Notification to let us refocus the same one after recreating views. protected: virtual void CreateViews(); virtual void sendMessage(const char *message, const char *value); - private: UI::EventReturn OnDefaultMapping(UI::EventParams ¶ms); UI::EventReturn OnClearMapping(UI::EventParams ¶ms); UI::EventReturn OnAutoConfigure(UI::EventParams ¶ms); virtual void dialogFinished(const Screen *dialog, DialogResult result) override; + + UI::ScrollView *rightScroll_; + std::vector mappers_; }; class KeyMappingNewKeyDialog : public PopupScreen { public: explicit KeyMappingNewKeyDialog(int btn, bool replace, std::function callback) - : PopupScreen("Map Key", "Cancel", ""), callback_(callback) { + : PopupScreen("Map Key", "Cancel", ""), callback_(callback), mapped_(false) { pspBtn_ = btn; } @@ -59,4 +65,5 @@ private: int pspBtn_; bool replace_; std::function callback_; + bool mapped_; // Prevent double registrations };