diff options
author | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2023-07-14 02:00:16 +0300 |
---|---|---|
committer | akleshchev <117672381+akleshchev@users.noreply.github.com> | 2023-07-17 15:46:18 +0300 |
commit | 4c89ad558688f6dfa8f7216ad7613ed75823b069 (patch) | |
tree | f475763d3047575e754fe655c610d304b1c492df /indra | |
parent | d573bc2f926fb6ff473d9b346cdeb4d73e3b0ab3 (diff) |
SL-19306 A method of displaying user-customized keybindings in user-visible text
Diffstat (limited to 'indra')
-rw-r--r-- | indra/llui/llurlentry.cpp | 121 | ||||
-rw-r--r-- | indra/llui/llurlentry.h | 33 | ||||
-rw-r--r-- | indra/llui/llurlregistry.cpp | 8 | ||||
-rw-r--r-- | indra/llui/llurlregistry.h | 6 | ||||
-rw-r--r-- | indra/llwindow/llkeyboard.cpp | 51 | ||||
-rw-r--r-- | indra/llwindow/llkeyboard.h | 9 | ||||
-rw-r--r-- | indra/newview/llappviewer.cpp | 2 | ||||
-rw-r--r-- | indra/newview/llfloaterpreference.cpp | 42 | ||||
-rw-r--r-- | indra/newview/llkeyconflict.cpp | 38 | ||||
-rw-r--r-- | indra/newview/llviewerinput.cpp | 92 | ||||
-rw-r--r-- | indra/newview/llviewerinput.h | 17 |
11 files changed, 360 insertions, 59 deletions
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 6a9070634c..77e9edf5e5 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -35,7 +35,9 @@ #include "llavatarnamecache.h" #include "llcachename.h" +#include "llkeyboard.h" #include "llregex.h" +#include "llscrolllistctrl.h" // for LLUrlEntryKeybinding file parsing #include "lltrans.h" #include "lluicolortable.h" #include "message.h" @@ -1609,3 +1611,122 @@ std::string LLUrlEntryIPv6::getUrl(const std::string &string) const { return string; } + + +// +// LLUrlEntryKeybinding Displays currently assigned key +// +LLUrlEntryKeybinding::LLUrlEntryKeybinding() + : LLUrlEntryBase() + , pHandler(NULL) +{ + mPattern = boost::regex(APP_HEADER_REGEX "/keybinding/\\w+(\\?mode=\\w+)?$", + boost::regex::perl | boost::regex::icase); + mMenuName = "menu_url_experience.xml"; + + initLocalization(); +} + +std::string LLUrlEntryKeybinding::getLabel(const std::string& url, const LLUrlLabelCallback& cb) +{ + std::string control = getControlName(url); + + std::map<std::string, LLLocalizationData>::iterator iter = mLocalizations.find(control); + + std::string keybind; + if (pHandler) + { + keybind = pHandler->getKeyBindingAsString(getMode(url), control); + } + + if (iter != mLocalizations.end()) + { + return iter->second.mLocalization + ": " + keybind; + } + + return control + ": " + keybind; +} + +std::string LLUrlEntryKeybinding::getTooltip(const std::string& url) const +{ + std::string control = getControlName(url); + + std::map<std::string, LLLocalizationData>::const_iterator iter = mLocalizations.find(control); + if (iter != mLocalizations.end()) + { + return iter->second.mTooltip; + } + return url; +} + +std::string LLUrlEntryKeybinding::getControlName(const std::string& url) const +{ + std::string search = "/keybinding/"; + size_t pos_start = url.find(search); + if (pos_start == std::string::npos) + { + return std::string(); + } + pos_start += search.size(); + + size_t pos_end = url.find("?mode="); + if (pos_end == std::string::npos) + { + pos_end = url.size(); + } + return url.substr(pos_start, pos_end - pos_start); +} + +std::string LLUrlEntryKeybinding::getMode(const std::string& url) const +{ + std::string search = "?mode="; + size_t pos_start = url.find(search); + if (pos_start == std::string::npos) + { + return std::string(); + } + pos_start += search.size(); + return url.substr(pos_start, url.size() - pos_start); +} + +void LLUrlEntryKeybinding::initLocalization() +{ + initLocalizationFromFile("control_table_contents_movement.xml"); + initLocalizationFromFile("control_table_contents_camera.xml"); + initLocalizationFromFile("control_table_contents_editing.xml"); + initLocalizationFromFile("control_table_contents_media.xml"); +} + +void LLUrlEntryKeybinding::initLocalizationFromFile(const std::string& filename) +{ + LLXMLNodePtr xmlNode; + LLScrollListCtrl::Contents contents; + if (!LLUICtrlFactory::getLayeredXMLNode(filename, xmlNode)) + { + LL_WARNS() << "Failed to load " << filename << LL_ENDL; + return; + } + LLXUIParser parser; + parser.readXUI(xmlNode, contents, filename); + + if (!contents.validateBlock()) + { + LL_WARNS() << "Failed to validate " << filename << LL_ENDL; + return; + } + + for (LLInitParam::ParamIterator<LLScrollListItem::Params>::const_iterator row_it = contents.rows.begin(); + row_it != contents.rows.end(); + ++row_it) + { + std::string control = row_it->value.getValue().asString(); + if (!control.empty() && control != "menu_separator") + { + mLocalizations[control] = + LLLocalizationData( + row_it->columns.begin()->value.getValue().asString(), + row_it->columns.begin()->tool_tip.getValue() + ); + } + } +} diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 63a1506731..5d0f5479f6 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -550,4 +550,37 @@ public: std::string mHostPath; }; +class LLKeyBindingToStringHandler; + +/// +/// LLUrlEntryKeybinding A way to access keybindings and show currently used one in text. +/// secondlife:///app/keybinding/control_name +class LLUrlEntryKeybinding: public LLUrlEntryBase +{ +public: + LLUrlEntryKeybinding(); + /*virtual*/ std::string getLabel(const std::string& url, const LLUrlLabelCallback& cb); + /*virtual*/ std::string getTooltip(const std::string& url) const; + void setHandler(LLKeyBindingToStringHandler* handler) {pHandler = handler;} +private: + std::string getControlName(const std::string& url) const; + std::string getMode(const std::string& url) const; + void initLocalization(); + void initLocalizationFromFile(const std::string& filename); + + struct LLLocalizationData + { + LLLocalizationData() {} + LLLocalizationData(const std::string& localization, const std::string& tooltip) + : mLocalization(localization) + , mTooltip(tooltip) + {} + std::string mLocalization; + std::string mTooltip; + }; + + std::map<std::string, LLLocalizationData> mLocalizations; + LLKeyBindingToStringHandler* pHandler; +}; + #endif diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index 23f3dca3fb..3bd7321777 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -73,6 +73,8 @@ LLUrlRegistry::LLUrlRegistry() registerUrl(new LLUrlEntryPlace()); registerUrl(new LLUrlEntryInventory()); registerUrl(new LLUrlEntryExperienceProfile()); + mUrlEntryKeybinding = new LLUrlEntryKeybinding(); + registerUrl(mUrlEntryKeybinding); //LLUrlEntrySL and LLUrlEntrySLLabel have more common pattern, //so it should be registered in the end of list registerUrl(new LLUrlEntrySL()); @@ -307,3 +309,9 @@ bool LLUrlRegistry::isUrl(const LLWString &text) } return false; } + +void LLUrlRegistry::setKeybindingHandler(LLKeyBindingToStringHandler* handler) +{ + LLUrlEntryKeybinding *entry = (LLUrlEntryKeybinding*)mUrlEntryKeybinding; + entry->setHandler(handler); +} diff --git a/indra/llui/llurlregistry.h b/indra/llui/llurlregistry.h index efafe543ab..186447c0be 100644 --- a/indra/llui/llurlregistry.h +++ b/indra/llui/llurlregistry.h @@ -36,6 +36,8 @@ #include <string> #include <vector> +class LLKeyBindingToStringHandler; + /// This default callback for findUrl() simply ignores any label updates void LLUrlRegistryNullCallback(const std::string &url, const std::string &label, @@ -88,6 +90,9 @@ public: bool isUrl(const std::string &text); bool isUrl(const LLWString &text); + // Set handler for url registry to be capable of parsing and populating keybindings + void setKeybindingHandler(LLKeyBindingToStringHandler* handler); + private: std::vector<LLUrlEntryBase *> mUrlEntry; LLUrlEntryBase* mUrlEntryTrusted; @@ -96,6 +101,7 @@ private: LLUrlEntryBase* mUrlEntryHTTPLabel; LLUrlEntryBase* mUrlEntrySLLabel; LLUrlEntryBase* mUrlEntryNoLink; + LLUrlEntryBase* mUrlEntryKeybinding; }; #endif diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp index e65cc7563e..34720ff64e 100644 --- a/indra/llwindow/llkeyboard.cpp +++ b/indra/llwindow/llkeyboard.cpp @@ -367,6 +367,45 @@ std::string LLKeyboard::stringFromKey(KEY key, bool translate) } //static +std::string LLKeyboard::stringFromMouse(EMouseClickType click, bool translate) +{ + std::string res; + switch (click) + { + case CLICK_LEFT: + res = "LMB"; + break; + case CLICK_MIDDLE: + res = "MMB"; + break; + case CLICK_RIGHT: + res = "RMB"; + break; + case CLICK_BUTTON4: + res = "MB4"; + break; + case CLICK_BUTTON5: + res = "MB5"; + break; + case CLICK_DOUBLELEFT: + res = "Double LMB"; + break; + default: + break; + } + + if (translate && !res.empty()) + { + LLKeyStringTranslatorFunc* trans = gKeyboard->mStringTranslator; + if (trans != NULL) + { + res = trans(res.c_str()); + } + } + return res; +} + +//static std::string LLKeyboard::stringFromAccelerator(MASK accel_mask) { std::string res; @@ -433,6 +472,18 @@ std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key ) return res; } +//static +std::string LLKeyboard::stringFromAccelerator(MASK accel_mask, EMouseClickType click) +{ + std::string res; + if (CLICK_NONE == click) + { + return res; + } + res.append(stringFromAccelerator(accel_mask)); + res.append(stringFromMouse(click)); + return res; +} //static BOOL LLKeyboard::maskFromString(const std::string& str, MASK *mask) diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h index fb1ae10f50..dad150e3c1 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -96,8 +96,10 @@ public: static BOOL maskFromString(const std::string& str, MASK *mask); // False on failure static BOOL keyFromString(const std::string& str, KEY *key); // False on failure static std::string stringFromKey(KEY key, bool translate = true); + static std::string stringFromMouse(EMouseClickType click, bool translate = true); static std::string stringFromAccelerator( MASK accel_mask ); // separated for convinience, returns with "+": "Shift+" or "Shift+Alt+"... static std::string stringFromAccelerator( MASK accel_mask, KEY key ); + static std::string stringFromAccelerator(MASK accel_mask, EMouseClickType click); void setCallbacks(LLWindowCallbacks *cbs) { mCallbacks = cbs; } F32 getKeyElapsedTime( KEY key ); // Returns time in seconds since key was pressed. @@ -130,6 +132,13 @@ protected: static std::map<std::string,KEY> sNamesToKeys; }; +// Interface to get key from assigned command +class LLKeyBindingToStringHandler +{ +public: + virtual std::string getKeyBindingAsString(const std::string& mode, const std::string& control) const = 0; +}; + extern LLKeyboard *gKeyboard; #endif diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 8235e4466c..3d81d4d7ea 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -195,6 +195,7 @@ #include "llhudeffecttrail.h" #include "llvectorperfoptions.h" #include "llslurl.h" +#include "llurlregistry.h" #include "llwatchdog.h" // Included so that constants/settings might be initialized @@ -4447,6 +4448,7 @@ void LLAppViewer::loadKeyBindings() LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL; } } + LLUrlRegistry::instance().setKeybindingHandler(&gViewerInput); } void LLAppViewer::purgeCache() diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 9ea49e935f..e59c2ee2cd 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -251,11 +251,49 @@ void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator) } } } -// static -std::string LLFloaterPreference::sSkin = ""; + +// handle secondlife:///app/worldmap/{NAME}/{COORDS} URLs +// Also see LLUrlEntryKeybinding, the value of this command type +// is ability to show up to date value in chat +class LLKeybindingHandler: public LLCommandHandler +{ +public: + // requires trusted browser to trigger + LLKeybindingHandler(): LLCommandHandler("keybinding", UNTRUSTED_CLICK_ONLY) + { + } + + bool handle(const LLSD& params, const LLSD& query_map, + LLMediaCtrl* web) + { + if (params.size() < 1) return false; + + LLFloaterPreference* prefsfloater = dynamic_cast<LLFloaterPreference*> + (LLFloaterReg::showInstance("preferences")); + + if (prefsfloater) + { + // find 'controls' panel and bring it the front + LLTabContainer* tabcontainer = prefsfloater->getChild<LLTabContainer>("pref core"); + LLPanel* panel = prefsfloater->getChild<LLPanel>("controls"); + if (tabcontainer && panel) + { + tabcontainer->selectTabPanel(panel); + } + } + + return true; + } +}; +LLKeybindingHandler gKeybindHandler; + + ////////////////////////////////////////////// // LLFloaterPreference +// static +std::string LLFloaterPreference::sSkin = ""; + LLFloaterPreference::LLFloaterPreference(const LLSD& key) : LLFloater(key), mGotPersonalInfo(false), diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp index 60f8aca94c..4a0ee8fd0c 100644 --- a/indra/newview/llkeyconflict.cpp +++ b/indra/newview/llkeyconflict.cpp @@ -74,40 +74,6 @@ std::string string_from_mask(MASK mask) return res; } -std::string string_from_mouse(EMouseClickType click, bool translate) -{ - std::string res; - switch (click) - { - case CLICK_LEFT: - res = "LMB"; - break; - case CLICK_MIDDLE: - res = "MMB"; - break; - case CLICK_RIGHT: - res = "RMB"; - break; - case CLICK_BUTTON4: - res = "MB4"; - break; - case CLICK_BUTTON5: - res = "MB5"; - break; - case CLICK_DOUBLELEFT: - res = "Double LMB"; - break; - default: - break; - } - - if (translate && !res.empty()) - { - res = LLTrans::getString(res); - } - return res; -} - // LLKeyConflictHandler S32 LLKeyConflictHandler::sTemporaryFileUseCount = 0; @@ -270,7 +236,7 @@ std::string LLKeyConflictHandler::getStringFromKeyData(const LLKeyData& keydata) result = LLKeyboard::stringFromAccelerator(keydata.mMask); } - result += string_from_mouse(keydata.mMouse, true); + result += LLKeyboard::stringFromMouse(keydata.mMouse); return result; } @@ -545,7 +511,7 @@ void LLKeyConflictHandler::saveToSettings(bool temporary) { // set() because 'optional', for compatibility purposes // just copy old keys.xml and rename to key_bindings.xml, it should work - binding.mouse.set(string_from_mouse(data.mMouse, false), true); + binding.mouse.set(LLKeyboard::stringFromMouse(data.mMouse, false), true); } binding.command = iter->first; mode.bindings.add(binding); diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp index 226e0a9a56..3f8e6f57f6 100644 --- a/indra/newview/llviewerinput.cpp +++ b/indra/newview/llviewerinput.cpp @@ -991,34 +991,50 @@ LLViewerInput::LLViewerInput() } } +LLViewerInput::~LLViewerInput() +{ + +} + // static -BOOL LLViewerInput::modeFromString(const std::string& string, S32 *mode) +bool LLViewerInput::modeFromString(const std::string& string, S32 *mode) { - if (string == "FIRST_PERSON") + if (string.empty()) + { + return false; + } + + std::string cmp_string = string; + LLStringUtil::toLower(cmp_string); + if (cmp_string == "first_person") { *mode = MODE_FIRST_PERSON; - return TRUE; + return true; } - else if (string == "THIRD_PERSON") + else if (cmp_string == "third_person") { *mode = MODE_THIRD_PERSON; - return TRUE; + return true; } - else if (string == "EDIT_AVATAR") + else if (cmp_string == "edit_avatar") { *mode = MODE_EDIT_AVATAR; - return TRUE; + return true; } - else if (string == "SITTING") + else if (cmp_string == "sitting") { *mode = MODE_SITTING; - return TRUE; - } - else - { - *mode = MODE_THIRD_PERSON; - return FALSE; + return true; } + + S32 val = atoi(string.c_str()); + if (val >= 0 || val < MODE_COUNT) + { + *mode = val; + return true; + } + + return false; } // static @@ -1222,6 +1238,7 @@ BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, cons bind.mKey = key; bind.mMask = mask; bind.mFunction = function; + bind.mFunctionName = function_name; if (result->mIsGlobal) { @@ -1303,6 +1320,7 @@ BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const bind.mMouse = mouse; bind.mMask = mask; bind.mFunction = function; + bind.mFunctionName = function_name; if (result->mIsGlobal) { @@ -1801,3 +1819,49 @@ bool LLViewerInput::isMouseBindUsed(const EMouseClickType mouse, const MASK mask } return false; } + +std::string LLViewerInput::getKeyBindingAsString(const std::string& mode, const std::string& control) const +{ + S32 keyboard_mode; + if (!modeFromString(mode, &keyboard_mode)) + { + keyboard_mode = getMode(); + } + + std::string res; + bool needs_separator = false; + + // keybindings are sorted from having most mask to no mask (from restrictive to less restrictive), + // but it's visually better to present this data in reverse + std::vector<LLKeyboardBinding>::const_reverse_iterator iter_key = mKeyBindings[keyboard_mode].rbegin(); + while (iter_key != mKeyBindings[keyboard_mode].rend()) + { + if (iter_key->mFunctionName == control) + { + if (needs_separator) + { + res.append(" | "); + } + res.append(LLKeyboard::stringFromAccelerator(iter_key->mMask, iter_key->mKey)); + needs_separator = true; + } + iter_key++; + } + + std::vector<LLMouseBinding>::const_reverse_iterator iter_mouse = mMouseBindings[keyboard_mode].rbegin(); + while (iter_mouse != mMouseBindings[keyboard_mode].rend()) + { + if (iter_mouse->mFunctionName == control) + { + if (needs_separator) + { + res.append(" | "); + } + res.append(LLKeyboard::stringFromAccelerator(iter_mouse->mMask, iter_mouse->mMouse)); + needs_separator = true; + } + iter_mouse++; + } + + return res; +} diff --git a/indra/newview/llviewerinput.h b/indra/newview/llviewerinput.h index 52e95e2168..41e289ac1d 100644 --- a/indra/newview/llviewerinput.h +++ b/indra/newview/llviewerinput.h @@ -28,12 +28,13 @@ #define LL_LLVIEWERINPUT_H #include "llkeyboard.h" // For EKeystate -#include "llinitparam.h" const S32 MAX_KEY_BINDINGS = 128; // was 60 const S32 keybindings_xml_version = 1; const std::string script_mouse_handler_name = "script_trigger_lbutton"; +class LLWindow; + class LLNamedFunction { public: @@ -51,6 +52,7 @@ public: MASK mMask; LLKeyFunc mFunction; + std::string mFunctionName; }; class LLMouseBinding @@ -60,6 +62,7 @@ public: MASK mMask; LLKeyFunc mFunction; + std::string mFunctionName; }; @@ -72,11 +75,7 @@ typedef enum e_keyboard_mode MODE_COUNT } EKeyboardMode; -class LLWindow; - -void bind_keyboard_functions(); - -class LLViewerInput +class LLViewerInput : public LLKeyBindingToStringHandler { public: struct KeyBinding : public LLInitParam::Block<KeyBinding> @@ -107,6 +106,7 @@ public: }; LLViewerInput(); + virtual ~LLViewerInput(); BOOL handleKey(KEY key, MASK mask, BOOL repeated); BOOL handleKeyUp(KEY key, MASK mask); @@ -121,7 +121,7 @@ public: S32 loadBindingsXML(const std::string& filename); // returns number bound, 0 on error EKeyboardMode getMode() const; - static BOOL modeFromString(const std::string& string, S32 *mode); // False on failure + static bool modeFromString(const std::string& string, S32 *mode); // False on failure static BOOL mouseFromString(const std::string& string, EMouseClickType *mode);// False on failure bool scanKey(KEY key, @@ -136,6 +136,9 @@ public: bool isMouseBindUsed(const EMouseClickType mouse, const MASK mask, const S32 mode) const; bool isLMouseHandlingDefault(const S32 mode) const { return mLMouseDefaultHandling[mode]; } + // inherited from LLKeyBindingToStringHandler + virtual std::string getKeyBindingAsString(const std::string& mode, const std::string& control) const override; + private: bool scanKey(const std::vector<LLKeyboardBinding> &binding, S32 binding_count, |