From c0ed4b6ff5301a7c90b32e3f552f84b84ee80465 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Thu, 31 Oct 2019 20:22:27 +0200 Subject: SL-11913 Favorites not resetting properly --- indra/newview/llpanellogin.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index d7c189271e..fd76a36044 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -41,7 +41,6 @@ #include "llcommandhandler.h" // for secondlife:///app/login/ #include "llcombobox.h" #include "llviewercontrol.h" -#include "llfloaterpreference.h" #include "llfocusmgr.h" #include "lllineeditor.h" #include "llnotificationsutil.h" @@ -456,6 +455,10 @@ void LLPanelLogin::addFavoritesToStartLocation() } break; } + if (combo->getValue().asString().empty()) + { + combo->selectFirstItem(); + } } LLPanelLogin::~LLPanelLogin() @@ -1275,13 +1278,13 @@ void LLPanelLogin::onSelectServer() { std::string location = location_combo->getValue().asString(); LLSLURL slurl(location); // generata a slurl from the location combo contents - if ( slurl.getType() == LLSLURL::LOCATION - && slurl.getGrid() != LLGridManager::getInstance()->getGrid() - ) + if (location.empty() + || (slurl.getType() == LLSLURL::LOCATION + && slurl.getGrid() != LLGridManager::getInstance()->getGrid()) + ) { // the grid specified by the location is not this one, so clear the combo location_combo->setCurrentByIndex(0); // last location on the new grid - location_combo->setTextEntry(LLStringUtil::null); } } break; -- cgit v1.2.3 From aadbb3d912af1184fd9c5210e5066d9d92e0dacd Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Thu, 31 Oct 2019 23:17:10 +0200 Subject: SL-11732 Validation for stored favorites --- indra/newview/llfavoritesbar.cpp | 29 +++++++++++++++++++++++------ indra/newview/llfavoritesbar.h | 5 ++++- 2 files changed, 27 insertions(+), 7 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 17952349dc..347997a69a 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1590,14 +1590,29 @@ void LLFavoritesOrderStorage::load() << (fav_llsd.isMap() ? "" : "un") << "successfully" << LL_ENDL; in_file.close(); - user_llsd = fav_llsd[gAgentUsername]; + if (fav_llsd.isMap() && fav_llsd.has(gAgentUsername)) + { + user_llsd = fav_llsd[gAgentUsername]; - S32 index = 0; - for (LLSD::array_iterator iter = user_llsd.beginArray(); + S32 index = 0; + bool needs_validation = gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"); + for (LLSD::array_iterator iter = user_llsd.beginArray(); iter != user_llsd.endArray(); ++iter) - { - mSortIndexes.insert(std::make_pair(iter->get("id").asUUID(), index)); - index++; + { + // Validation + LLUUID fv_id = iter->get("id").asUUID(); + if (needs_validation + && (fv_id.isNull() + || iter->get("asset_id").asUUID().isNull() + || iter->get("name").asString().empty() + || iter->get("slurl").asString().empty())) + { + mRecreateFavoriteStorage = true; + } + + mSortIndexes.insert(std::make_pair(fv_id, index)); + index++; + } } } else @@ -1841,6 +1856,8 @@ void LLFavoritesOrderStorage::rearrangeFavoriteLandmarks(const LLUUID& source_it BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed) { + pref_changed |= mRecreateFavoriteStorage; + mRecreateFavoriteStorage = false; LLUUID favorite_folder= gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); if (favorite_folder.isNull()) diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index d93161fd7a..571208aa31 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -248,6 +248,7 @@ private: slurls_map_t mSLURLs; std::set mMissingSLURLs; bool mIsDirty; + bool mRecreateFavoriteStorage; struct IsNotInFavorites { @@ -278,7 +279,9 @@ private: inline LLFavoritesOrderStorage::LLFavoritesOrderStorage() : - mIsDirty(false), mUpdateRequired(false) + mIsDirty(false), + mUpdateRequired(false), + mRecreateFavoriteStorage(false) { load(); } #endif // LL_LLFAVORITESBARCTRL_H -- cgit v1.2.3 From dcb1bea0f6086d963fba8b374d0294223bf66a11 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Thu, 19 Sep 2019 16:55:28 +0300 Subject: SL-6109 Implement keybindings --- indra/newview/llfloaterpreference.cpp | 14 ++++++------- indra/newview/llfloaterpreference.h | 2 +- indra/newview/lltool.cpp | 2 +- indra/newview/lltool.h | 2 +- indra/newview/lltoolpie.cpp | 2 +- indra/newview/lltoolpie.h | 2 +- indra/newview/llviewerwindow.cpp | 39 ++++++++++++++++------------------- indra/newview/llviewerwindow.h | 2 +- indra/newview/llvoiceclient.cpp | 8 +++---- indra/newview/llvoiceclient.h | 2 +- 10 files changed, 36 insertions(+), 39 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index b48495b5b2..9282196b86 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -170,7 +170,7 @@ public: void setParent(LLFloaterPreference* parent) { mParent = parent; } BOOL handleKeyHere(KEY key, MASK mask); - BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down); + BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); static void onCancel(void* user_data); private: @@ -214,11 +214,11 @@ BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask) return result; } -BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down) +BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) { BOOL result = FALSE; if (down - && (clicktype == LLMouseHandler::CLICK_MIDDLE || clicktype == LLMouseHandler::CLICK_BUTTON4 || clicktype == LLMouseHandler::CLICK_BUTTON5) + && (clicktype == CLICK_MIDDLE || clicktype == CLICK_BUTTON4 || clicktype == CLICK_BUTTON5) && mask == 0) { mParent->setMouse(clicktype); @@ -1717,21 +1717,21 @@ void LLFloaterPreference::setKey(KEY key) getChild("modifier_combo")->onCommit(); } -void LLFloaterPreference::setMouse(LLMouseHandler::EClickType click) +void LLFloaterPreference::setMouse(EMouseClickType click) { std::string bt_name; std::string ctrl_value; switch (click) { - case LLMouseHandler::CLICK_MIDDLE: + case CLICK_MIDDLE: bt_name = "middle_mouse"; ctrl_value = MIDDLE_MOUSE_CV; break; - case LLMouseHandler::CLICK_BUTTON4: + case CLICK_BUTTON4: bt_name = "button4_mouse"; ctrl_value = MOUSE_BUTTON_4_CV; break; - case LLMouseHandler::CLICK_BUTTON5: + case CLICK_BUTTON5: bt_name = "button5_mouse"; ctrl_value = MOUSE_BUTTON_5_CV; break; diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 4412c95473..9190ef8ebd 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -148,7 +148,7 @@ public: void onSelectSkin(); void onClickSetKey(); void setKey(KEY key); - void setMouse(LLMouseHandler::EClickType click); + void setMouse(EMouseClickType click); void onClickSetMiddleMouse(); void onClickSetSounds(); void onClickEnablePopup(); diff --git a/indra/newview/lltool.cpp b/indra/newview/lltool.cpp index c5e31ff8e6..0038138078 100644 --- a/indra/newview/lltool.cpp +++ b/indra/newview/lltool.cpp @@ -60,7 +60,7 @@ LLTool::~LLTool() } } -BOOL LLTool::handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down) +BOOL LLTool::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) { BOOL result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down); diff --git a/indra/newview/lltool.h b/indra/newview/lltool.h index 308983afda..41a38804ce 100644 --- a/indra/newview/lltool.h +++ b/indra/newview/lltool.h @@ -49,7 +49,7 @@ public: virtual BOOL isView() const { return FALSE; } // Virtual functions inherited from LLMouseHandler - virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down); + virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 6c1ae7159b..0b569b4fe8 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -91,7 +91,7 @@ LLToolPie::LLToolPie() { } -BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down) +BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) { BOOL result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down); diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index fe0acfe473..6d0e25eaeb 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -42,7 +42,7 @@ class LLToolPie : public LLTool, public LLSingleton public: // Virtual functions inherited from LLMouseHandler - virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down); + virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 1e2b2c37d0..2c58295814 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -898,7 +898,7 @@ LLViewerWindow::Params::Params() {} -BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down) +BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down) { const char* buttonname = ""; const char* buttonstatestr = ""; @@ -907,6 +907,8 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK x = ll_round((F32)x / mDisplayScale.mV[VX]); y = ll_round((F32)y / mDisplayScale.mV[VY]); + LLVoiceClient::getInstance()->updateMouseState(clicktype, mask, down); + // only send mouse clicks to UI if UI is visible if(gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) { @@ -922,26 +924,26 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK switch (clicktype) { - case LLMouseHandler::CLICK_LEFT: + case CLICK_LEFT: mLeftMouseDown = down; buttonname = "Left"; break; - case LLMouseHandler::CLICK_RIGHT: + case CLICK_RIGHT: mRightMouseDown = down; buttonname = "Right"; break; - case LLMouseHandler::CLICK_MIDDLE: + case CLICK_MIDDLE: mMiddleMouseDown = down; buttonname = "Middle"; break; - case LLMouseHandler::CLICK_DOUBLELEFT: + case CLICK_DOUBLELEFT: mLeftMouseDown = down; buttonname = "Left Double Click"; break; - case LLMouseHandler::CLICK_BUTTON4: + case CLICK_BUTTON4: buttonname = "Button 4"; break; - case LLMouseHandler::CLICK_BUTTON5: + case CLICK_BUTTON5: buttonname = "Button 5"; break; } @@ -1059,7 +1061,7 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask mMouseDownTimer.reset(); } BOOL down = TRUE; - return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down); + return handleAnyMouseClick(window, pos, mask, CLICK_LEFT, down); } BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask) @@ -1067,8 +1069,7 @@ BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK ma // try handling as a double-click first, then a single-click if that // wasn't handled. BOOL down = TRUE; - if (handleAnyMouseClick(window, pos, mask, - LLMouseHandler::CLICK_DOUBLELEFT, down)) + if (handleAnyMouseClick(window, pos, mask, CLICK_DOUBLELEFT, down)) { return TRUE; } @@ -1082,7 +1083,7 @@ BOOL LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) mMouseDownTimer.stop(); } BOOL down = FALSE; - return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down); + return handleAnyMouseClick(window, pos, mask, CLICK_LEFT, down); } @@ -1094,7 +1095,7 @@ BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK y = ll_round((F32)y / mDisplayScale.mV[VY]); BOOL down = TRUE; - BOOL handle = handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down); + BOOL handle = handleAnyMouseClick(window, pos, mask, CLICK_RIGHT, down); if (handle) return handle; @@ -1115,14 +1116,13 @@ BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) { BOOL down = FALSE; - return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down); + return handleAnyMouseClick(window, pos, mask, CLICK_RIGHT, down); } BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask) { BOOL down = TRUE; - LLVoiceClient::getInstance()->updateMouseState(LLMouseHandler::CLICK_MIDDLE, true); - handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down); + handleAnyMouseClick(window, pos, mask, CLICK_MIDDLE, down); // Always handled as far as the OS is concerned. return TRUE; @@ -1277,8 +1277,7 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) { BOOL down = FALSE; - LLVoiceClient::getInstance()->updateMouseState(LLMouseHandler::CLICK_MIDDLE, false); - handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down); + handleAnyMouseClick(window, pos, mask, CLICK_MIDDLE, down); // Always handled as far as the OS is concerned. return TRUE; @@ -1289,12 +1288,10 @@ BOOL LLViewerWindow::handleOtherMouse(LLWindow *window, LLCoordGL pos, MASK mask switch (button) { case 4: - LLVoiceClient::getInstance()->updateMouseState(LLMouseHandler::CLICK_BUTTON4, down); - handleAnyMouseClick(window, pos, mask, LLMouseHandler::CLICK_BUTTON4, down); + handleAnyMouseClick(window, pos, mask, CLICK_BUTTON4, down); break; case 5: - LLVoiceClient::getInstance()->updateMouseState(LLMouseHandler::CLICK_BUTTON5, down); - handleAnyMouseClick(window, pos, mask, LLMouseHandler::CLICK_BUTTON5, down); + handleAnyMouseClick(window, pos, mask, CLICK_BUTTON5, down); break; default: break; diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 385bbd57e5..5f03685cee 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -176,7 +176,7 @@ public: void setUIVisibility(bool); bool getUIVisibility(); - BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down); + BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down); // // LLWindowCallback interface implementation diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index bce399a940..e7a8a78c14 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -641,15 +641,15 @@ void LLVoiceClient::setPTTKey(std::string &key) // Value is stored as text for readability if(key == "MiddleMouse") { - mPTTMouseButton = LLMouseHandler::CLICK_MIDDLE; + mPTTMouseButton = CLICK_MIDDLE; } else if(key == "MouseButton4") { - mPTTMouseButton = LLMouseHandler::CLICK_BUTTON4; + mPTTMouseButton = CLICK_BUTTON4; } else if (key == "MouseButton5") { - mPTTMouseButton = LLMouseHandler::CLICK_BUTTON5; + mPTTMouseButton = CLICK_BUTTON5; } else { @@ -711,7 +711,7 @@ void LLVoiceClient::keyUp(KEY key, MASK mask) } } } -void LLVoiceClient::updateMouseState(S32 click, bool down) +void LLVoiceClient::updateMouseState(S32 click, MASK mask, bool down) { if(mPTTMouseButton == click && LLAgent::isActionAllowed("speak")) { diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index fbc85fd977..e3285b0c9b 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -418,7 +418,7 @@ public: // PTT key triggering void keyDown(KEY key, MASK mask); void keyUp(KEY key, MASK mask); - void updateMouseState(S32 click, bool down); + void updateMouseState(S32 click, MASK mask, bool down); boost::signals2::connection MicroChangedCallback(const micro_changed_signal_t::slot_type& cb ) { return mMicroChangedSignal.connect(cb); } -- cgit v1.2.3 From 50719510630768d65c9f00043676f287c58ca110 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Mon, 19 Aug 2019 23:16:29 +0300 Subject: SL_6109 Rebinding --- indra/newview/llfloaterpreference.cpp | 330 ++++++++++++++++++++- indra/newview/llfloaterpreference.h | 21 ++ indra/newview/llspatialpartition.cpp | 2 +- indra/newview/llvoiceclient.cpp | 7 +- .../skins/default/xui/en/floater_preferences.xml | 7 + .../default/xui/en/panel_preferences_controls.xml | 196 ++++++++++++ 6 files changed, 553 insertions(+), 10 deletions(-) create mode 100644 indra/newview/skins/default/xui/en/panel_preferences_controls.xml (limited to 'indra/newview') diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 9282196b86..182341685b 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -52,6 +52,7 @@ #include "llfavoritesbar.h" #include "llfloatersidepanelcontainer.h" #include "llfloaterimsession.h" +#include "llkeybindings.h" #include "llkeyboard.h" #include "llmodaldialog.h" #include "llnavigationbar.h" @@ -168,6 +169,7 @@ public: /*virtual*/ BOOL postBuild(); void setParent(LLFloaterPreference* parent) { mParent = parent; } + void setTmpParent(LLPanelPreferenceControls* parent) { mTmpParent = parent; } // todo: voice key will be removed, class renamved, so it will have only one parent BOOL handleKeyHere(KEY key, MASK mask); BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); @@ -175,11 +177,13 @@ public: private: LLFloaterPreference* mParent; + LLPanelPreferenceControls* mTmpParent;// todo: voice key will be removed, class renamved, so it will have only one parent }; LLVoiceSetKeyDialog::LLVoiceSetKeyDialog(const LLSD& key) : LLModalDialog(key), - mParent(NULL) + mParent(NULL), + mTmpParent(NULL) { } @@ -201,15 +205,30 @@ LLVoiceSetKeyDialog::~LLVoiceSetKeyDialog() BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask) { BOOL result = TRUE; + + if (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT || key == KEY_NONE) + { + // temp + return false; + } + // todo, same for escape if (key == 'Q' && mask == MASK_CONTROL) { result = FALSE; - } + if (mTmpParent) + { + mTmpParent->onSetKey(KEY_NONE, MASK_NONE); + } + } else if (mParent) { mParent->setKey(key); } + else if (mTmpParent) + { + mTmpParent->onSetKey(key, mask); + } closeFloater(); return result; } @@ -217,11 +236,38 @@ BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask) BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) { BOOL result = FALSE; - if (down - && (clicktype == CLICK_MIDDLE || clicktype == CLICK_BUTTON4 || clicktype == CLICK_BUTTON5) - && mask == 0) + + if (clicktype == CLICK_LEFT) + { + if (down) + { + result = LLView::handleMouseDown(x, y, mask); + } + else + { + result = LLView::handleMouseUp(x, y, mask); + } + } + if (clicktype == LLMouseHandler::CLICK_LEFT) + { + result = LLView::handleDoubleClick(x, y, mask); + } + if (result) + { + return TRUE; + } + if (down && clicktype != LLMouseHandler::CLICK_RIGHT) //tmp + //&& (clicktype == LLMouseHandler::CLICK_MIDDLE || clicktype == LLMouseHandler::CLICK_BUTTON4 || clicktype == LLMouseHandler::CLICK_BUTTON5) + //&& mask == 0) { - mParent->setMouse(clicktype); + if (mParent) + { + mParent->setMouse(clicktype); + } + else if (mTmpParent) + { + mTmpParent->onSetMouse(clicktype, mask); + } result = TRUE; closeFloater(); } @@ -237,6 +283,11 @@ BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseCli void LLVoiceSetKeyDialog::onCancel(void* user_data) { LLVoiceSetKeyDialog* self = (LLVoiceSetKeyDialog*)user_data; + // tmp needs 'no key' button + if (self->mTmpParent) + { + self->mTmpParent->onSetKey(KEY_NONE, MASK_NONE); + } self->closeFloater(); } @@ -2914,6 +2965,273 @@ void LLPanelPreferenceGraphics::setHardwareDefaults() resetDirtyChilds(); } + +//-------------------For LLPanelPreferenceControls' list--------------------------- +class LLGroupControlsListItem : public LLScrollListItem, public LLHandleProvider +{ +public: + LLGroupControlsListItem(const LLScrollListItem::Params& p) + : LLScrollListItem(p) + { + } + + LLGroupControlsListItem(const LLScrollListItem::Params& p, const LLUUID& icon_id) + : LLScrollListItem(p), mIconId(icon_id) + { + } + + void draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding) + { + // todo: insert image and adjust rect + LLScrollListItem::draw(rect, fg_color, bg_color, highlight_color, column_padding); + } +private: + LLUUID mIconId; +}; + +static const std::string tmp_typetostring[LLControlBindings::CONTROL_NUM_INDICES] = { + "control_view_actions", + "control_about", + "control_orbit", + "control_pan", + "control_world_map", + "control_zoom", + "control_interactions", + "control_build", + "control_drag", + "control_edit", + "control_menu", + "control_open", + "control_touch", + "control_wear", + "control_movements", + "control_moveto", + "control_sit", + "control_teleportto", + "control_forward", + "control_backward", + "control_left", + "control_right", + "control_lstrafe", + "control_rstrafe", + "control_jump", + "control_down", + "control_run", + "control_toggle_run", + "control_fly", + "control_mediacontent", + "control_parcel", + "control_media", + "control_voice", + "control_toggle_voice", + "control_reserved", + "control_menu", + "control_reserved_select", + "control_shift_select", + "control_cntrl_select" +}; + +//------------------------LLPanelPreferenceControls-------------------------------- +static LLPanelInjector t_pref_contrls("panel_preference_controls"); + +BOOL LLPanelPreferenceControls::postBuild() +{ + //todo: on open instead of on the go + //todo: add pitch/yaw? + //todo: Scroll? + //todo: should be auto-expandable with menu items and should pull names from menu when possible + + + // populate list of controls + pControlsTable = getChild("controls_list"); + populateControlTable(); + + pControlsTable->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onListCommit, this)); + + return TRUE; +} + +void LLPanelPreferenceControls::populateControlTable() +{ + pControlsTable->clearRows(); + + // todo: subsections need sorting? + std::string label; + LLScrollListCell::Params cell_params; + // init basic cell params + cell_params.font = LLFontGL::getFontSansSerif(); + cell_params.font_halign = LLFontGL::LEFT; + cell_params.column = ""; + cell_params.value = label; + + LLScrollListItem::Params item_params_blank; + cell_params.enabled = false; + item_params_blank.value = LLSD::Integer(-1); + item_params_blank.columns.add(cell_params); + cell_params.enabled = true; + + for (U32 i = LLControlBindings::CONTROL_VIEW_ACTIONS; i < LLControlBindings::CONTROL_NUM_INDICES; i++) + { + switch (i) + { + case LLControlBindings::CONTROL_VIEW_ACTIONS: + { + // same as below, but without separator + LLScrollListItem::Params item_params; + item_params.value = LLSD::Integer(i); + + label = getString(tmp_typetostring[i]); + cell_params.column = "lst_action"; + cell_params.value = label; + //dummy cells + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl1"; + cell_params.value = ""; + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl2"; + cell_params.value = ""; + item_params.columns.add(cell_params); + LLUUID id; + LLGroupControlsListItem* item = new LLGroupControlsListItem(item_params, id); + pControlsTable->addRow(item, item_params, EAddPosition::ADD_BOTTOM); + break; + } + case LLControlBindings::CONTROL_INTERACTIONS: + case LLControlBindings::CONTROL_MOVEMENTS: + case LLControlBindings::CONTROL_MEDIACONTENT: + case LLControlBindings::CONTROL_RESERVED: + { + // insert blank + pControlsTable->addRow(item_params_blank, EAddPosition::ADD_BOTTOM); + // inster with icon + LLScrollListItem::Params item_params; + item_params.value = LLSD::Integer(i); + + label = getString(tmp_typetostring[i]); + cell_params.column = "lst_action"; + cell_params.value = label; + //dummy cells + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl1"; + cell_params.value = ""; + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl2"; + cell_params.value = ""; + item_params.columns.add(cell_params); + LLUUID id; + LLGroupControlsListItem* item = new LLGroupControlsListItem(item_params, id); + pControlsTable->addRow(item, item_params, EAddPosition::ADD_BOTTOM); + break; + } + default: + { + //default insert + LLScrollListItem::Params item_params; + item_params.value = LLSD::Integer(i); + + // todo oddset + cell_params.column = "lst_action"; + label = getString(tmp_typetostring[i]); + cell_params.value = label; + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl1"; + cell_params.value = gControlBindings.getPrimaryControl((LLControlBindings::EControlTypes)i).asString(); + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl2"; + cell_params.value = gControlBindings.getSecondaryControl((LLControlBindings::EControlTypes)i).asString(); + item_params.columns.add(cell_params); + + pControlsTable->addRow(item_params, EAddPosition::ADD_BOTTOM); + break; + } + } + } +} + +void LLPanelPreferenceControls::cancel() +{ +} + +void LLPanelPreferenceControls::saveSettings() +{ +} + +void LLPanelPreferenceControls::resetDirtyChilds() +{ +} + +bool LLPanelPreferenceControls::hasDirtyChilds() +{ + return false; +} + +void LLPanelPreferenceControls::onListCommit() +{ + LLScrollListItem* item = pControlsTable->getFirstSelected(); + if (item == NULL) + { + return; + } + + S32 control = item->getValue().asInteger(); + + if (!gControlBindings.canAssignControl((LLControlBindings::EControlTypes)control)) + { + return; + } + + // todo: add code to determine what cell was clicked, probably cells themself should be clickable + + LLVoiceSetKeyDialog* dialog = LLFloaterReg::showTypedInstance("voice_set_key", LLSD(), TRUE); + if (dialog) + { + dialog->setTmpParent(this); // will be remade from being voice later + } +} + +void LLPanelPreferenceControls::onSetKey(KEY key, MASK mask) +{ + LLScrollListItem* item = pControlsTable->getFirstSelected(); + if (item == NULL) + { + return; + } + + LLControlBindings::EControlTypes control = (LLControlBindings::EControlTypes)item->getValue().asInteger(); + + if (!gControlBindings.canAssignControl(control)) + { + return; + } + + gControlBindings.registerPrimaryControl(control, LLMouseHandler::CLICK_NONE, key, mask); + + // instead of populating, update single element + populateControlTable(); +} + +void LLPanelPreferenceControls::onSetMouse(LLMouseHandler::EClickType click, MASK mask) +{ + + LLScrollListItem* item = pControlsTable->getFirstSelected(); + if (item == NULL) + { + return; + } + + LLControlBindings::EControlTypes control = (LLControlBindings::EControlTypes)item->getValue().asInteger(); + + if (!gControlBindings.canAssignControl(control)) + { + return; + } + + gControlBindings.registerPrimaryControl(control, click, KEY_NONE, mask); + + // instead of populating, update single element + populateControlTable(); +} + LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const LLSD& key) : LLFloater(key) { diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 9190ef8ebd..74f55a7f91 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -293,6 +293,27 @@ private: LOG_CLASS(LLPanelPreferenceGraphics); }; +class LLPanelPreferenceControls : public LLPanelPreference +{ + LOG_CLASS(LLPanelPreferenceControls); +public: + BOOL postBuild(); + void populateControlTable(); + void cancel(); + void saveSettings(); + void resetDirtyChilds(); + + void onListCommit(); + void onSetKey(KEY key, MASK mask); + void onSetMouse(LLMouseHandler::EClickType click, MASK mask); + +protected: + bool hasDirtyChilds(); + +private: + LLScrollListCtrl* pControlsTable; +}; + class LLFloaterPreferenceGraphicsAdvanced : public LLFloater { public: diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 1dc1e65fe5..7e6f3ef7bc 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -996,7 +996,7 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible) } LLSpatialGroup* group = drawablep->getSpatialGroup(); - llassert(group != NULL); + //llassert(group != NULL); if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING)) { diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index e7a8a78c14..676f06bcb9 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -35,6 +35,7 @@ #include "llnotificationsutil.h" #include "llsdserialize.h" #include "llui.h" +#include "llkeybindings.h" #include "llkeyboard.h" #include "llagent.h" @@ -690,7 +691,7 @@ void LLVoiceClient::keyDown(KEY key, MASK mask) return; } - if (mPTTMouseButton == 0 && LLAgent::isActionAllowed("speak") && (key == mPTTKey)) + if (LLAgent::isActionAllowed("speak") && gControlBindings.canHandleKey(LLControlBindings::CONTROL_VOICE, key, mask)) { bool down = gKeyboard->getKeyDown(mPTTKey); if (down) @@ -702,7 +703,7 @@ void LLVoiceClient::keyDown(KEY key, MASK mask) } void LLVoiceClient::keyUp(KEY key, MASK mask) { - if (mPTTMouseButton == 0 && (key == mPTTKey)) + if (gControlBindings.canHandleKey(LLControlBindings::CONTROL_VOICE, key, mask)) { bool down = gKeyboard->getKeyDown(mPTTKey); if (!down) @@ -713,7 +714,7 @@ void LLVoiceClient::keyUp(KEY key, MASK mask) } void LLVoiceClient::updateMouseState(S32 click, MASK mask, bool down) { - if(mPTTMouseButton == click && LLAgent::isActionAllowed("speak")) + if(LLAgent::isActionAllowed("speak") && gControlBindings.canHandleMouse(LLControlBindings::CONTROL_VOICE, click, mask)) { inputUserControlState(down); } diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml index 0e62d50072..ee730dcb01 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences.xml @@ -169,6 +169,13 @@ https://accounts.secondlife.com/change_email/ layout="topleft" help_topic="preferences_uploads_tab" name="uploads" /> + diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml new file mode 100644 index 0000000000..a1a2fd0598 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml @@ -0,0 +1,196 @@ + + + + View Actions + + + About/Profile + + + Orbit + + + Pan + + + World Map + + + Zoom + + + Interactions + + + Build + + + Drag + + + Edit + + + Menu + + + Open + + + Touch + + + Wear + + + Move Actions + + + Move To + + + Sit/Stand + + + Teleport To + + + Move Forward + + + Move Backward + + + Left + + + Right + + + + Strafe left + + + Strafe right + + + Strafe right + + + Strafe right + + + Run + + + Toggle Run + + + Fly/Stop flying + + + Sound and Media + + + Play/Pause Parcel Media + + + Play/Stop All Media + + + Voice + + + Toggle Voice + + + Reserved Controls + + + + Select + + + Multi-Select + + + Add to Selection + + + + + + + + + + -- cgit v1.2.3 From c21812bf095de2defa4e61978b2659764c838abf Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Tue, 17 Sep 2019 21:36:59 +0300 Subject: SL-6109 Keyaboard support ready --- indra/newview/CMakeLists.txt | 2 + indra/newview/llfloaterpreference.cpp | 680 ++++++++++-------- indra/newview/llfloaterpreference.h | 31 +- indra/newview/llkeyconflict.cpp | 789 +++++++++++++++++++++ indra/newview/llkeyconflict.h | 214 ++++++ indra/newview/llviewerkeyboard.cpp | 56 +- indra/newview/llviewerkeyboard.h | 6 +- indra/newview/llvoiceclient.cpp | 18 +- .../skins/default/xui/en/floater_select_key.xml | 40 +- .../default/xui/en/panel_preferences_controls.xml | 161 ++++- 10 files changed, 1620 insertions(+), 377 deletions(-) create mode 100644 indra/newview/llkeyconflict.cpp create mode 100644 indra/newview/llkeyconflict.h (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 6089162190..bfbe1a0cfd 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -376,6 +376,7 @@ set(viewer_SOURCE_FILES llinventoryobserver.cpp llinventorypanel.cpp lljoystickbutton.cpp + llkeyconflict.cpp lllandmarkactions.cpp lllandmarklist.cpp lllistbrowser.cpp @@ -1004,6 +1005,7 @@ set(viewer_HEADER_FILES llinventoryobserver.h llinventorypanel.h lljoystickbutton.h + llkeyconflict.h lllandmarkactions.h lllandmarklist.h lllightconstants.h diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 182341685b..4a4f66db14 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -52,7 +52,6 @@ #include "llfavoritesbar.h" #include "llfloatersidepanelcontainer.h" #include "llfloaterimsession.h" -#include "llkeybindings.h" #include "llkeyboard.h" #include "llmodaldialog.h" #include "llnavigationbar.h" @@ -72,8 +71,9 @@ #include "lltrans.h" #include "llviewercontrol.h" #include "llviewercamera.h" -#include "llviewerwindow.h" +#include "llviewereventrecorder.h" #include "llviewermessage.h" +#include "llviewerwindow.h" #include "llviewershadermgr.h" #include "llviewerthrottle.h" #include "llvoavatarself.h" @@ -160,36 +160,49 @@ struct LabelTable : public LLInitParam::Block {} }; -class LLVoiceSetKeyDialog : public LLModalDialog +// Filters for LLSetKeyBindDialog +static const U32 ALLOW_MOUSE = 1; +static const U32 ALLOW_MASK_MOUSE = 2; +static const U32 ALLOW_KEYS = 4; //keyboard +static const U32 ALLOW_MASK_KEYS = 8; +static const U32 ALLOW_MASKS = 16; +static const U32 IGNORE_MASKS = 32; // For example W (aka Forward) should work regardless of SHIFT being pressed +static const U32 DEFAULT_KEY_FILTER = ALLOW_MOUSE | ALLOW_MASK_MOUSE | ALLOW_KEYS | ALLOW_MASK_KEYS; + +class LLSetKeyBindDialog : public LLModalDialog { public: - LLVoiceSetKeyDialog(const LLSD& key); - ~LLVoiceSetKeyDialog(); - + LLSetKeyBindDialog(const LLSD& key); + ~LLSetKeyBindDialog(); + /*virtual*/ BOOL postBuild(); - - void setParent(LLFloaterPreference* parent) { mParent = parent; } - void setTmpParent(LLPanelPreferenceControls* parent) { mTmpParent = parent; } // todo: voice key will be removed, class renamved, so it will have only one parent - + + void setParent(LLPanelPreferenceControls* parent, U32 key_mask = DEFAULT_KEY_FILTER); + BOOL handleKeyHere(KEY key, MASK mask); BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); static void onCancel(void* user_data); - + static void onBlank(void* user_data); + static void onDefault(void* user_data); + private: - LLFloaterPreference* mParent; - LLPanelPreferenceControls* mTmpParent;// todo: voice key will be removed, class renamved, so it will have only one parent + LLPanelPreferenceControls* mParent; + + U32 mKeyMask; }; -LLVoiceSetKeyDialog::LLVoiceSetKeyDialog(const LLSD& key) +LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key) : LLModalDialog(key), mParent(NULL), - mTmpParent(NULL) + mKeyMask(DEFAULT_KEY_FILTER) { } //virtual -BOOL LLVoiceSetKeyDialog::postBuild() +BOOL LLSetKeyBindDialog::postBuild() { + childSetAction("SetEmpty", onBlank, this); + childSetAction("Default", onDefault, this); childSetAction("Cancel", onCancel, this); getChild("Cancel")->setFocus(TRUE); @@ -198,47 +211,85 @@ BOOL LLVoiceSetKeyDialog::postBuild() return TRUE; } -LLVoiceSetKeyDialog::~LLVoiceSetKeyDialog() +void LLSetKeyBindDialog::setParent(LLPanelPreferenceControls* parent, U32 key_mask) +{ + mParent = parent; + mKeyMask = key_mask; + + LLTextBase *text_ctrl = getChild("descritption"); + + std::string input; + if ((key_mask & ALLOW_MOUSE) != 0) + { + input = getString("mouse"); + } + if ((key_mask & ALLOW_KEYS) != 0) + { + if (!input.empty()) + { + input += ", "; + } + input += getString("keyboard"); + } + text_ctrl->setTextArg("[INPUT]", input); +} + +LLSetKeyBindDialog::~LLSetKeyBindDialog() { } -BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask) +BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask) { BOOL result = TRUE; - if (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT || key == KEY_NONE) + if ((key == 'Q' && mask == MASK_CONTROL) + || key == KEY_ESCAPE) + { + closeFloater(); + return true; + } + + // forbidden keys + if (key == KEY_NONE + || key == KEY_RETURN + || key == KEY_DELETE + || key == KEY_BACKSPACE) { - // temp return false; } - - // todo, same for escape - if (key == 'Q' && mask == MASK_CONTROL) - { - result = FALSE; - if (mTmpParent) - { - mTmpParent->onSetKey(KEY_NONE, MASK_NONE); - } + + if ((mKeyMask & ALLOW_MASKS) == 0 + && (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT)) + { + // mask by themself are not allowed + return false; + } + else if ((mKeyMask & ALLOW_KEYS) == 0) + { + // basic keys not allowed + return false; + } + else if ((mKeyMask & ALLOW_MASK_KEYS) == 0 && mask != 0) + { + // masked keys not allowed + return false; } + else if (mParent) { - mParent->setKey(key); - } - else if (mTmpParent) - { - mTmpParent->onSetKey(key, mask); + mParent->onSetKeyBind(CLICK_NONE, key, mask); } closeFloater(); return result; } -BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) +BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) { BOOL result = FALSE; if (clicktype == CLICK_LEFT) { + // try handling buttons first if (down) { result = LLView::handleMouseDown(x, y, mask); @@ -248,30 +299,21 @@ BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseCli result = LLView::handleMouseUp(x, y, mask); } } - if (clicktype == LLMouseHandler::CLICK_LEFT) - { - result = LLView::handleDoubleClick(x, y, mask); - } - if (result) - { - return TRUE; - } - if (down && clicktype != LLMouseHandler::CLICK_RIGHT) //tmp - //&& (clicktype == LLMouseHandler::CLICK_MIDDLE || clicktype == LLMouseHandler::CLICK_BUTTON4 || clicktype == LLMouseHandler::CLICK_BUTTON5) - //&& mask == 0) + + if (!result + && ((mKeyMask & ALLOW_MOUSE) != 0) + && (clicktype != CLICK_RIGHT || mask != 0) // reassigning menu button is not supported + && ((mKeyMask & ALLOW_MASK_MOUSE) != 0 || mask == 0)) { if (mParent) { - mParent->setMouse(clicktype); - } - else if (mTmpParent) - { - mTmpParent->onSetMouse(clicktype, mask); + mParent->onSetKeyBind(clicktype, KEY_NONE, mask); } result = TRUE; closeFloater(); } - else + + if (!result) { result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down); } @@ -280,17 +322,36 @@ BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseCli } //static -void LLVoiceSetKeyDialog::onCancel(void* user_data) +void LLSetKeyBindDialog::onCancel(void* user_data) { - LLVoiceSetKeyDialog* self = (LLVoiceSetKeyDialog*)user_data; - // tmp needs 'no key' button - if (self->mTmpParent) - { - self->mTmpParent->onSetKey(KEY_NONE, MASK_NONE); - } + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; self->closeFloater(); } +//static +void LLSetKeyBindDialog::onBlank(void* user_data) +{ + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; + // tmp needs 'no key' button + if (self->mParent) + { + self->mParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE); + } + self->closeFloater(); +} + +//static +void LLSetKeyBindDialog::onDefault(void* user_data) +{ + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; + // tmp needs 'no key' button + if (self->mParent) + { + self->mParent->onDefaultKeyBind(); + } + self->closeFloater(); +} + // global functions @@ -370,37 +431,6 @@ void handleAppearanceCameraMovementChanged(const LLSD& newvalue) } } -/*bool callback_skip_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option && floater ) - { - if ( floater ) - { - floater->setAllIgnored(); - // LLFirstUse::disableFirstUse(); - floater->buildPopupLists(); - } - } - return false; -} - -bool callback_reset_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if ( 0 == option && floater ) - { - if ( floater ) - { - floater->resetAllIgnored(); - //LLFirstUse::resetFirstUse(); - floater->buildPopupLists(); - } - } - return false; -} -*/ - void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator) { numerator = 0; @@ -435,7 +465,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) static bool registered_dialog = false; if (!registered_dialog) { - LLFloaterReg::add("voice_set_key", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("keybind_dialog", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); registered_dialog = true; } @@ -1754,53 +1784,6 @@ void LLFloaterPreference::onChangeQuality(const LLSD& data) void LLFloaterPreference::onClickSetKey() { - LLVoiceSetKeyDialog* dialog = LLFloaterReg::showTypedInstance("voice_set_key", LLSD(), TRUE); - if (dialog) - { - dialog->setParent(this); - } -} - -void LLFloaterPreference::setKey(KEY key) -{ - getChild("modifier_combo")->setValue(LLKeyboard::stringFromKey(key)); - // update the control right away since we no longer wait for apply - getChild("modifier_combo")->onCommit(); -} - -void LLFloaterPreference::setMouse(EMouseClickType click) -{ - std::string bt_name; - std::string ctrl_value; - switch (click) - { - case CLICK_MIDDLE: - bt_name = "middle_mouse"; - ctrl_value = MIDDLE_MOUSE_CV; - break; - case CLICK_BUTTON4: - bt_name = "button4_mouse"; - ctrl_value = MOUSE_BUTTON_4_CV; - break; - case CLICK_BUTTON5: - bt_name = "button5_mouse"; - ctrl_value = MOUSE_BUTTON_5_CV; - break; - default: - break; - } - - if (!ctrl_value.empty()) - { - LLUICtrl* p2t_line_editor = getChild("modifier_combo"); - // We are using text control names for readability and compatibility with voice - p2t_line_editor->setControlValue(ctrl_value); - LLPanel* advanced_preferences = dynamic_cast(p2t_line_editor->getParent()); - if (advanced_preferences) - { - p2t_line_editor->setValue(advanced_preferences->getString(bt_name)); - } - } } void LLFloaterPreference::onClickSetMiddleMouse() @@ -1825,18 +1808,6 @@ void LLFloaterPreference::onClickSetSounds() getChild("gesture_audio_play_btn")->setEnabled(!gSavedSettings.getBOOL("MuteSounds")); } -/* -void LLFloaterPreference::onClickSkipDialogs() -{ - LLNotificationsUtil::add("SkipShowNextTimeDialogs", LLSD(), LLSD(), boost::bind(&callback_skip_dialogs, _1, _2, this)); -} - -void LLFloaterPreference::onClickResetDialogs() -{ - LLNotificationsUtil::add("ResetShowNextTimeDialogs", LLSD(), LLSD(), boost::bind(&callback_reset_dialogs, _1, _2, this)); -} - */ - void LLFloaterPreference::onClickEnablePopup() { LLScrollListCtrl& disabled_popups = getChildRef("disabled_popups"); @@ -2845,7 +2816,7 @@ void LLPanelPreferenceGraphics::setPresetText() } } - if (hasDirtyChilds() && !preset_graphic_active.empty()) + if (hasDirtyChilds() && !preset_graphic_active.empty()) { gSavedSettings.setString("PresetGraphicActive", ""); preset_graphic_active.clear(); @@ -2965,98 +2936,124 @@ void LLPanelPreferenceGraphics::setHardwareDefaults() resetDirtyChilds(); } +//------------------------LLPanelPreferenceControls-------------------------------- +static LLPanelInjector t_pref_contrls("panel_preference_controls"); -//-------------------For LLPanelPreferenceControls' list--------------------------- -class LLGroupControlsListItem : public LLScrollListItem, public LLHandleProvider +LLPanelPreferenceControls::LLPanelPreferenceControls() + :LLPanelPreference(), + mEditingIndex(-1), + mEditingColumn(-1), + mEditingMode(0), + mShowKeyDialog(false) { -public: - LLGroupControlsListItem(const LLScrollListItem::Params& p) - : LLScrollListItem(p) - { - } - - LLGroupControlsListItem(const LLScrollListItem::Params& p, const LLUUID& icon_id) - : LLScrollListItem(p), mIconId(icon_id) - { - } - - void draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding) - { - // todo: insert image and adjust rect - LLScrollListItem::draw(rect, fg_color, bg_color, highlight_color, column_padding); - } -private: - LLUUID mIconId; -}; - -static const std::string tmp_typetostring[LLControlBindings::CONTROL_NUM_INDICES] = { - "control_view_actions", - "control_about", - "control_orbit", - "control_pan", - "control_world_map", - "control_zoom", - "control_interactions", - "control_build", - "control_drag", - "control_edit", - "control_menu", - "control_open", - "control_touch", - "control_wear", - "control_movements", - "control_moveto", - "control_sit", - "control_teleportto", - "control_forward", - "control_backward", - "control_left", - "control_right", - "control_lstrafe", - "control_rstrafe", - "control_jump", - "control_down", - "control_run", - "control_toggle_run", - "control_fly", - "control_mediacontent", - "control_parcel", - "control_media", - "control_voice", - "control_toggle_voice", - "control_reserved", - "control_menu", - "control_reserved_select", - "control_shift_select", - "control_cntrl_select" -}; +} -//------------------------LLPanelPreferenceControls-------------------------------- -static LLPanelInjector t_pref_contrls("panel_preference_controls"); +LLPanelPreferenceControls::~LLPanelPreferenceControls() +{ +} BOOL LLPanelPreferenceControls::postBuild() { - //todo: on open instead of on the go //todo: add pitch/yaw? - //todo: Scroll? //todo: should be auto-expandable with menu items and should pull names from menu when possible // populate list of controls pControlsTable = getChild("controls_list"); - populateControlTable(); + pKeyModeBox = getChild("key_mode"); pControlsTable->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onListCommit, this)); + pKeyModeBox->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onModeCommit, this)); + getChild("restore_defaults")->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onRestoreDefaults, this)); return TRUE; } +// Something of a workaround: cells don't handle clicks, so we catch a click, then process it on hover. +BOOL LLPanelPreferenceControls::handleHover(S32 x, S32 y, MASK mask) +{ + if (mShowKeyDialog) + { + if (mEditingIndex > 0 && mConflictHandler[mEditingMode].canAssignControl((LLKeyConflictHandler::EControlTypes)mEditingIndex)) + { + mEditingColumn = pControlsTable->getColumnIndexFromOffset(x); + + if (mEditingColumn >0) + { + LLSetKeyBindDialog* dialog = LLFloaterReg::showTypedInstance("keybind_dialog", LLSD(), TRUE); + if (dialog) + { + if (mConflictHandler[mEditingMode].getLoadedMode() == LLKeyConflictHandler::MODE_GENERAL) + { + dialog->setParent(this, DEFAULT_KEY_FILTER); + } + else + { + dialog->setParent(this, ALLOW_KEYS | ALLOW_MASK_KEYS); + } + } + } + } + mShowKeyDialog = false; + } + return LLPanelPreference::handleHover(x, y, mask); +} + +void LLPanelPreferenceControls::addGroupRow(const std::string &icon, S32 index) +{ + LLScrollListItem::Params item_params; + item_params.value = LLSD::Integer(-1); + + LLScrollListCell::Params icon_cell_params; + icon_cell_params.font = LLFontGL::getFontSansSerif(); + icon_cell_params.font_halign = LLFontGL::LEFT; + icon_cell_params.type = "icontext"; + + LLScrollListCell::Params cell_params; + // init basic cell params + cell_params.font = LLFontGL::getFontSansSerif(); + cell_params.font_halign = LLFontGL::LEFT; + + std::string control_name = LLKeyConflictHandler::getControlName((LLKeyConflictHandler::EControlTypes)index); + std::string label; + if (hasString(control_name)) + { + label = getString(control_name); + } + else + { + label = control_name; + } + icon_cell_params.column = "lst_action"; + icon_cell_params.text = label; + icon_cell_params.value = icon; + item_params.columns.add(icon_cell_params); + //dummy cells + cell_params.column = "lst_ctrl1"; + cell_params.value = ""; + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl2"; + cell_params.value = ""; + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl3"; + cell_params.value = ""; + item_params.columns.add(cell_params); + pControlsTable->addRow(item_params, EAddPosition::ADD_BOTTOM); +} + +void LLPanelPreferenceControls::regenerateControls() +{ + mEditingMode = pKeyModeBox->getValue().asInteger(); + mConflictHandler[mEditingMode].loadFromSettings((LLKeyConflictHandler::EModes)mEditingMode); + populateControlTable(); +} + void LLPanelPreferenceControls::populateControlTable() { pControlsTable->clearRows(); // todo: subsections need sorting? - std::string label; + std::string label, control_name; LLScrollListCell::Params cell_params; // init basic cell params cell_params.font = LLFontGL::getFontSansSerif(); @@ -3064,81 +3061,71 @@ void LLPanelPreferenceControls::populateControlTable() cell_params.column = ""; cell_params.value = label; - LLScrollListItem::Params item_params_blank; - cell_params.enabled = false; - item_params_blank.value = LLSD::Integer(-1); - item_params_blank.columns.add(cell_params); - cell_params.enabled = true; - - for (U32 i = LLControlBindings::CONTROL_VIEW_ACTIONS; i < LLControlBindings::CONTROL_NUM_INDICES; i++) + S32 start = mEditingMode == LLKeyConflictHandler::MODE_GENERAL ? LLKeyConflictHandler::CONTROL_VIEW_ACTIONS : LLKeyConflictHandler::CONTROL_MOVEMENTS; + S32 end = mEditingMode == LLKeyConflictHandler::MODE_GENERAL ? LLKeyConflictHandler::CONTROL_NUM_INDICES : LLKeyConflictHandler::CONTROL_RESERVED; + for (S32 i = start; i < end; i++) { - switch (i) + LLKeyConflictHandler::EControlTypes type = (LLKeyConflictHandler::EControlTypes)i; + switch (type) { - case LLControlBindings::CONTROL_VIEW_ACTIONS: - { - // same as below, but without separator - LLScrollListItem::Params item_params; - item_params.value = LLSD::Integer(i); - - label = getString(tmp_typetostring[i]); - cell_params.column = "lst_action"; - cell_params.value = label; - //dummy cells - item_params.columns.add(cell_params); - cell_params.column = "lst_ctrl1"; - cell_params.value = ""; - item_params.columns.add(cell_params); - cell_params.column = "lst_ctrl2"; - cell_params.value = ""; - item_params.columns.add(cell_params); - LLUUID id; - LLGroupControlsListItem* item = new LLGroupControlsListItem(item_params, id); - pControlsTable->addRow(item, item_params, EAddPosition::ADD_BOTTOM); - break; - } - case LLControlBindings::CONTROL_INTERACTIONS: - case LLControlBindings::CONTROL_MOVEMENTS: - case LLControlBindings::CONTROL_MEDIACONTENT: - case LLControlBindings::CONTROL_RESERVED: - { - // insert blank - pControlsTable->addRow(item_params_blank, EAddPosition::ADD_BOTTOM); - // inster with icon - LLScrollListItem::Params item_params; - item_params.value = LLSD::Integer(i); - - label = getString(tmp_typetostring[i]); - cell_params.column = "lst_action"; - cell_params.value = label; - //dummy cells - item_params.columns.add(cell_params); - cell_params.column = "lst_ctrl1"; - cell_params.value = ""; - item_params.columns.add(cell_params); - cell_params.column = "lst_ctrl2"; - cell_params.value = ""; - item_params.columns.add(cell_params); - LLUUID id; - LLGroupControlsListItem* item = new LLGroupControlsListItem(item_params, id); - pControlsTable->addRow(item, item_params, EAddPosition::ADD_BOTTOM); - break; - } - default: + case LLKeyConflictHandler::CONTROL_VIEW_ACTIONS: + addSeparator(); + addGroupRow("Search_Icon", i); + break; + case LLKeyConflictHandler::CONTROL_INTERACTIONS: + addSeparator(); + addGroupRow("Command_Gestures_Icon", i); + break; + case LLKeyConflictHandler::CONTROL_MOVEMENTS: + addSeparator(); + addGroupRow("Move_Walk_Off", i); + break; + case LLKeyConflictHandler::CONTROL_MEDIACONTENT: + addSeparator(); + addGroupRow("Audio_Press", i); + break; + case LLKeyConflictHandler::CONTROL_CAMERA: + addSeparator(); + addGroupRow("Cam_FreeCam_Off", i); + break; + case LLKeyConflictHandler::CONTROL_EDIT_TITLE: + addSeparator(); + addGroupRow("Tool_Dozer", i); + break; + case LLKeyConflictHandler::CONTROL_RESERVED: + addSeparator(); + addGroupRow("Info_Small", i); + break; + default: { //default insert LLScrollListItem::Params item_params; item_params.value = LLSD::Integer(i); - // todo oddset cell_params.column = "lst_action"; - label = getString(tmp_typetostring[i]); + bool enabled = mConflictHandler[mEditingMode].canAssignControl(type); + control_name = LLKeyConflictHandler::getControlName(type); + if (hasString(control_name)) + { + label = getString(control_name); + } + else + { + label = control_name; + } cell_params.value = label; item_params.columns.add(cell_params); cell_params.column = "lst_ctrl1"; - cell_params.value = gControlBindings.getPrimaryControl((LLControlBindings::EControlTypes)i).asString(); + cell_params.value = mConflictHandler[mEditingMode].getControlString(type, 0); + cell_params.enabled = enabled; item_params.columns.add(cell_params); cell_params.column = "lst_ctrl2"; - cell_params.value = gControlBindings.getSecondaryControl((LLControlBindings::EControlTypes)i).asString(); + cell_params.value = mConflictHandler[mEditingMode].getControlString(type, 1); + cell_params.enabled = enabled; + item_params.columns.add(cell_params); + cell_params.column = "lst_ctrl3"; + cell_params.value = mConflictHandler[mEditingMode].getControlString(type, 2); + cell_params.enabled = enabled; item_params.columns.add(cell_params); pControlsTable->addRow(item_params, EAddPosition::ADD_BOTTOM); @@ -3146,23 +3133,64 @@ void LLPanelPreferenceControls::populateControlTable() } } } + + //temp + if (mEditingMode == LLKeyConflictHandler::MODE_GENERAL) + pControlsTable->setEnabled(false); } -void LLPanelPreferenceControls::cancel() +// Just a workaround to not care about first separator before headers (we can start from random header) +void LLPanelPreferenceControls::addSeparator() { + if (pControlsTable->getItemCount() > 0) + { + pControlsTable->addSeparator(EAddPosition::ADD_BOTTOM); + } } -void LLPanelPreferenceControls::saveSettings() +void LLPanelPreferenceControls::apply() { + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i) + { + if (mConflictHandler[i].hasUnsavedChanges()) + { + mConflictHandler[i].saveToSettings(); + } + } } -void LLPanelPreferenceControls::resetDirtyChilds() +void LLPanelPreferenceControls::cancel() { + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i) + { + if (mConflictHandler[i].hasUnsavedChanges()) + { + mConflictHandler[i].clear(); + } + } + pControlsTable->clear(); } -bool LLPanelPreferenceControls::hasDirtyChilds() +void LLPanelPreferenceControls::saveSettings() { - return false; + for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i) + { + if (mConflictHandler[i].hasUnsavedChanges()) + { + mConflictHandler[i].saveToSettings(); + } + } + + S32 mode = pKeyModeBox->getValue().asInteger(); + if (mConflictHandler[mode].empty()) + { + regenerateControls(); + } +} + +void LLPanelPreferenceControls::resetDirtyChilds() +{ + regenerateControls(); } void LLPanelPreferenceControls::onListCommit() @@ -3175,61 +3203,85 @@ void LLPanelPreferenceControls::onListCommit() S32 control = item->getValue().asInteger(); - if (!gControlBindings.canAssignControl((LLControlBindings::EControlTypes)control)) + if (control <= 0) { return; } - - // todo: add code to determine what cell was clicked, probably cells themself should be clickable - LLVoiceSetKeyDialog* dialog = LLFloaterReg::showTypedInstance("voice_set_key", LLSD(), TRUE); - if (dialog) + if (!mConflictHandler[mEditingMode].canAssignControl((LLKeyConflictHandler::EControlTypes)control)) { - dialog->setTmpParent(this); // will be remade from being voice later + return; } + + // List does not tell us what cell was clicked, so we have to figure it out manually, but + // fresh mouse coordinates are not yet accessible during onCommit() and there are other issues, + // so we cheat: remember item user clicked at, trigger 'key dialog' on hover that comes next, + // use coordinates from hover to calculate cell + mEditingIndex = control; + mShowKeyDialog = true; } -void LLPanelPreferenceControls::onSetKey(KEY key, MASK mask) +void LLPanelPreferenceControls::onModeCommit() { - LLScrollListItem* item = pControlsTable->getFirstSelected(); - if (item == NULL) + regenerateControls(); +} + +void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask) +{ + LLKeyConflictHandler::EControlTypes control = (LLKeyConflictHandler::EControlTypes)mEditingIndex; + + if (!mConflictHandler[mEditingMode].canAssignControl(control)) { return; } - LLControlBindings::EControlTypes control = (LLControlBindings::EControlTypes)item->getValue().asInteger(); - - if (!gControlBindings.canAssignControl(control)) + pControlsTable->deselectAllItems(); + pControlsTable->selectByValue(mEditingIndex); + LLScrollListItem *item = pControlsTable->getFirstSelected(); + if (item && mEditingColumn > 0) { - return; + + mConflictHandler[mEditingMode].registerControl(control, mEditingColumn - 1, click, key, mask); + + LLScrollListCell *cell = item->getColumn(1); + cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 0)); + cell = item->getColumn(2); + cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 1)); + cell = item->getColumn(3); + cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 2)); } - gControlBindings.registerPrimaryControl(control, LLMouseHandler::CLICK_NONE, key, mask); + populateControlTable(); +} - // instead of populating, update single element +void LLPanelPreferenceControls::onRestoreDefaults() +{ + mConflictHandler[mEditingMode].resetToDefaults(); populateControlTable(); } -void LLPanelPreferenceControls::onSetMouse(LLMouseHandler::EClickType click, MASK mask) +void LLPanelPreferenceControls::onDefaultKeyBind() { + LLKeyConflictHandler::EControlTypes control = (LLKeyConflictHandler::EControlTypes)mEditingIndex; - LLScrollListItem* item = pControlsTable->getFirstSelected(); - if (item == NULL) + if (!mConflictHandler[mEditingMode].canAssignControl(control)) { return; } - LLControlBindings::EControlTypes control = (LLControlBindings::EControlTypes)item->getValue().asInteger(); - - if (!gControlBindings.canAssignControl(control)) + pControlsTable->deselectAllItems(); + pControlsTable->selectByValue(mEditingIndex); + LLScrollListItem *item = pControlsTable->getFirstSelected(); + if (item) { - return; - } + LLScrollListCell *cell = item->getColumn(mEditingColumn); - gControlBindings.registerPrimaryControl(control, click, KEY_NONE, mask); - - // instead of populating, update single element - populateControlTable(); + if (mEditingColumn > 0) + { + mConflictHandler[mEditingMode].resetToDefault(control, mEditingColumn - 1); + cell->setValue(mConflictHandler[mEditingMode].getControlString(control, mEditingColumn - 1)); + } + } } LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const LLSD& key) diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 74f55a7f91..bce84387ab 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -37,12 +37,14 @@ #include "llavatarpropertiesprocessor.h" #include "llconversationlog.h" #include "llsearcheditor.h" +#include "llkeyconflict.h" class LLConversationLogObserver; class LLPanelPreference; class LLPanelLCD; class LLPanelDebug; class LLMessageSystem; +class LLComboBox; class LLScrollListCtrl; class LLSliderCtrl; class LLSD; @@ -147,8 +149,6 @@ public: void onClickSkin(LLUICtrl* ctrl,const LLSD& userdata); void onSelectSkin(); void onClickSetKey(); - void setKey(KEY key); - void setMouse(EMouseClickType click); void onClickSetMiddleMouse(); void onClickSetSounds(); void onClickEnablePopup(); @@ -297,21 +297,36 @@ class LLPanelPreferenceControls : public LLPanelPreference { LOG_CLASS(LLPanelPreferenceControls); public: + LLPanelPreferenceControls(); + ~LLPanelPreferenceControls(); + BOOL postBuild(); - void populateControlTable(); + BOOL handleHover(S32 x, S32 y, MASK mask); + + void apply(); void cancel(); void saveSettings(); void resetDirtyChilds(); void onListCommit(); - void onSetKey(KEY key, MASK mask); - void onSetMouse(LLMouseHandler::EClickType click, MASK mask); - -protected: - bool hasDirtyChilds(); + void onModeCommit(); + void onSetKeyBind(EMouseClickType click, KEY key, MASK mask); + void onRestoreDefaults(); + void onDefaultKeyBind(); private: + void addGroupRow(const std::string &icon, S32 index); + void regenerateControls(); + void populateControlTable(); + void addSeparator(); + LLScrollListCtrl* pControlsTable; + LLComboBox *pKeyModeBox; + LLKeyConflictHandler mConflictHandler[LLKeyConflictHandler::MODE_COUNT]; + S32 mEditingIndex; + S32 mEditingColumn; + S32 mEditingMode; + bool mShowKeyDialog; }; class LLFloaterPreferenceGraphicsAdvanced : public LLFloater diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp new file mode 100644 index 0000000000..0f0129bf68 --- /dev/null +++ b/indra/newview/llkeyconflict.cpp @@ -0,0 +1,789 @@ +/** + * @file llkeyconflict.cpp + * @brief + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2019, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +/* + * App-wide preferences. Note that these are not per-user, + * because we need to load many preferences before we have + * a login name. + */ + +#include "llviewerprecompiledheaders.h" + +#include "llkeyconflict.h" + +#include "llinitparam.h" +#include "llkeyboard.h" +#include "llviewercontrol.h" +#include "llviewerkeyboard.h" +#include "llxuiparser.h" +//#include "llstring.h" + +static const std::string typetostring[LLKeyConflictHandler::CONTROL_NUM_INDICES] = { + "control_view_actions", + "control_about", + "control_orbit", + "control_pan", + "control_world_map", + "control_zoom", + "control_interactions", + "control_build", + //"control_drag", + "control_edit", + //"control_menu", + "control_open", + "control_touch", + "control_wear", + "control_movements", + "control_moveto", + "control_sit", + "control_teleportto", + "push_forward", + "push_backward", + "turn_left", + "turn_right", + "slide_left", + "slide_right", + "jump", + "push_down", + //"control_run", + "control_toggle_run", + "toggle_fly", + "stop_moving", + "control_camera", + "look_up", + "look_down", + "move_forward", + "move_backward", + "move_forward_fast", + "move_backward_fast", + "move_forward_sitting", + "move_backward_sitting", + "spin_over", + "spin_under", + "spin_over_sitting", + "spin_under_sitting", + "pan_up", + "pan_down", + "pan_left", + "pan_right", + "pan_in", + "pan_out", + "spin_around_ccw", + "spin_around_cw", + "spin_around_ccw_sitting", + "spin_around_cw_sitting", + "control_edit_title", + "edit_avatar_spin_ccw", + "edit_avatar_spin_cw", + "edit_avatar_spin_over", + "edit_avatar_spin_under", + "edit_avatar_move_forward", + "edit_avatar_move_backward", + "control_mediacontent", + "control_parcel", + "control_media", + "control_voice", + "control_toggle_voice", + "start_chat", + "start_gesture", + "control_reserved", + "control_delete", + "control_menu", + "control_reserved_select", + "control_shift_select", + "control_cntrl_select" +}; + +// note, a solution is needed that will keep this up to date with llviewerkeyboard +typedef std::map control_enum_t; +static const control_enum_t command_to_key = +{ + { "jump", LLKeyConflictHandler::CONTROL_JUMP }, + { "push_down", LLKeyConflictHandler::CONTROL_DOWN }, + { "push_forward", LLKeyConflictHandler::CONTROL_FORWARD }, + { "push_backward", LLKeyConflictHandler::CONTROL_BACKWARD }, + { "look_up", LLKeyConflictHandler::CONTROL_LOOK_UP }, + { "look_down", LLKeyConflictHandler::CONTROL_LOOK_DOWN }, + { "toggle_fly", LLKeyConflictHandler::CONTROL_TOGGLE_FLY }, + { "turn_left", LLKeyConflictHandler::CONTROL_LEFT }, + { "turn_right", LLKeyConflictHandler::CONTROL_RIGHT }, + { "slide_left", LLKeyConflictHandler::CONTROL_LSTRAFE }, + { "slide_right", LLKeyConflictHandler::CONTROL_RSTRAFE }, + { "spin_around_ccw", LLKeyConflictHandler::CONTROL_CAMERA_SPIN_CCW }, // todo, no idea what these spins are + { "spin_around_cw", LLKeyConflictHandler::CONTROL_CAMERA_SPIN_CW }, + { "spin_around_ccw_sitting", LLKeyConflictHandler::CONTROL_CAMERA_SPIN_CCW_SITTING }, + { "spin_around_cw_sitting", LLKeyConflictHandler::CONTROL_CAMERA_SPIN_CCW_SITTING }, + { "spin_over", LLKeyConflictHandler::CONTROL_CAMERA_SOVER }, + { "spin_under", LLKeyConflictHandler::CONTROL_CAMERA_SUNDER }, + { "spin_over_sitting", LLKeyConflictHandler::CONTROL_CAMERA_SOVER_SITTING }, + { "spin_under_sitting", LLKeyConflictHandler::CONTROL_CAMERA_SUNDER_SITTING }, + { "move_forward", LLKeyConflictHandler::CONTROL_CAMERA_FORWARD }, + { "move_backward", LLKeyConflictHandler::CONTROL_CAMERA_BACKWARD }, + { "move_forward_sitting", LLKeyConflictHandler::CONTROL_CAMERA_FSITTING }, + { "move_backward_sitting", LLKeyConflictHandler::CONTROL_CAMERA_BSITTING }, + { "pan_up", LLKeyConflictHandler::CONTROL_CAMERA_PANUP }, + { "pan_down", LLKeyConflictHandler::CONTROL_CAMERA_PANDOWN }, + { "pan_left", LLKeyConflictHandler::CONTROL_CAMERA_PANLEFT }, + { "pan_right", LLKeyConflictHandler::CONTROL_CAMERA_PANRIGHT }, + { "pan_in", LLKeyConflictHandler::CONTROL_CAMERA_PANIN }, + { "pan_out", LLKeyConflictHandler::CONTROL_CAMERA_PANOUT }, + { "move_forward_fast", LLKeyConflictHandler::CONTROL_CAMERA_FFORWARD }, + { "move_backward_fast", LLKeyConflictHandler::CONTROL_CAMERA_FBACKWARD }, + { "edit_avatar_spin_ccw", LLKeyConflictHandler::CONTROL_EDIT_AV_SPIN_CCW }, + { "edit_avatar_spin_cw", LLKeyConflictHandler::CONTROL_EDIT_AV_SPIN_CW }, + { "edit_avatar_spin_over", LLKeyConflictHandler::CONTROL_EDIT_AV_SPIN_OVER }, + { "edit_avatar_spin_under", LLKeyConflictHandler::CONTROL_EDIT_AV_SPIN_UNDER }, + { "edit_avatar_move_forward", LLKeyConflictHandler::CONTROL_EDIT_AV_MV_FORWARD }, + { "edit_avatar_move_backward", LLKeyConflictHandler::CONTROL_EDIT_AV_MV_BACKWARD }, + { "stop_moving", LLKeyConflictHandler::CONTROL_STOP }, + { "start_chat", LLKeyConflictHandler::CONTROL_START_CHAT }, + { "start_gesture", LLKeyConflictHandler::CONTROL_START_GESTURE }, +}; + + +// LLKeyboard::stringFromMask is meant for UI and is OS dependent, +// so this class uses it's own version +std::string string_from_mask(MASK mask) +{ + std::string res; + if ((mask & MASK_CONTROL) != 0) + { + res = "CTL"; + } + if ((mask & MASK_ALT) != 0) + { + if (!res.empty()) res += "_"; + res += "ALT"; + } + if ((mask & MASK_SHIFT) != 0) + { + if (!res.empty()) res += "_"; + res += "SHIFT"; + } + + if (mask == MASK_NONE) + { + res = "NONE"; + } + return res; +} + +// LLKeyConflictHandler + +LLKeyConflictHandler::LLKeyConflictHandler() + : mHasUnsavedChanges(false) +{ + // todo: assign conflic priorities + // todo: load from keys.xml? + + // Thise controls are meant to cause conflicts when user tries to assign same control somewhere else + /*registerTemporaryControl(CONTROL_RESERVED_MENU, CLICK_RIGHT, KEY_NONE, MASK_NONE, 0); + registerTemporaryControl(CONTROL_SHIFT_SELECT, CLICK_LEFT, KEY_NONE, MASK_SHIFT, 0); + registerTemporaryControl(CONTROL_CNTRL_SELECT, CLICK_LEFT, KEY_NONE, MASK_CONTROL, 0); + registerTemporaryControl(CONTROL_DELETE, CLICK_NONE, KEY_DELETE, MASK_NONE, 0); + + loadFromSettings();*/ +} + +LLKeyConflictHandler::LLKeyConflictHandler(EModes mode) + : mHasUnsavedChanges(false), + mLoadedMode(mode) +{ + loadFromSettings(mode); +} + +bool LLKeyConflictHandler::canHandleControl(LLKeyConflictHandler::EControlTypes control_type, EMouseClickType mouse_ind, KEY key, MASK mask) +{ + return mControlsMap[control_type].canHandle(mouse_ind, key, mask); +} + +bool LLKeyConflictHandler::canHandleKey(EControlTypes control_type, KEY key, MASK mask) +{ + return canHandleControl(control_type, CLICK_NONE, key, mask); +} + +bool LLKeyConflictHandler::canHandleMouse(LLKeyConflictHandler::EControlTypes control_type, EMouseClickType mouse_ind, MASK mask) +{ + return canHandleControl(control_type, mouse_ind, KEY_NONE, mask); +} + +bool LLKeyConflictHandler::canHandleMouse(EControlTypes control_type, S32 mouse_ind, MASK mask) +{ + return canHandleControl(control_type, (EMouseClickType)mouse_ind, KEY_NONE, mask); +} + +bool LLKeyConflictHandler::canAssignControl(EControlTypes control_type) +{ + std::map::iterator iter = mControlsMap.find(control_type); + if (iter != mControlsMap.end()) + { + return iter->second.mAssignable; + } + return false; +} + +void LLKeyConflictHandler::registerControl(EControlTypes control_type, U32 index, EMouseClickType mouse, KEY key, MASK mask) +{ + LLKeyConflict &type_data = mControlsMap[control_type]; + if (!type_data.mAssignable) + { + LL_ERRS() << "Error in code, user or system should not be able to change certain controls" << LL_ENDL; + } + type_data.mKeyBind.replaceKeyData(mouse, key, mask, index); + + mHasUnsavedChanges = true; +} + +LLKeyData LLKeyConflictHandler::getControl(EControlTypes control_type, U32 index) +{ + return mControlsMap[control_type].getKeyData(index); +} + +// static +std::string LLKeyConflictHandler::getStringFromKeyData(const LLKeyData& keydata) +{ + std::string result; + + if (keydata.mMask != MASK_NONE && keydata.mKey != KEY_NONE) + { + result = LLKeyboard::stringFromAccelerator(keydata.mMask, keydata.mKey); + } + else if (keydata.mKey != KEY_NONE) + { + result = LLKeyboard::stringFromKey(keydata.mKey); + } + else if (keydata.mMask != MASK_NONE) + { + LL_ERRS() << "Masks binding without keys is not supported yet" << LL_ENDL; + } + + #ifdef LL_DARWIN + // darwin uses special symbols and doesn't need '+' for masks + if (mMouse != CLICK_NONE && mKey != KEY_NONE) + { + result += " + "; + } + #else + if (keydata.mMouse != CLICK_NONE && !result.empty()) + { + result += " + "; + } + #endif + + switch (keydata.mMouse) + { + case CLICK_LEFT: + result += "LMB"; + break; + case CLICK_MIDDLE: + result += "MMB"; + break; + case CLICK_RIGHT: + result += "RMB"; + break; + case CLICK_BUTTON4: + result += "MB4"; + break; + case CLICK_BUTTON5: + result += "MB5"; + break; + case CLICK_DOUBLELEFT: + result += "Double LMB"; + break; + default: + break; + } + return result; +} + +// static +std::string LLKeyConflictHandler::getControlName(EControlTypes control_type) +{ + return typetostring[control_type]; +} + +std::string LLKeyConflictHandler::getControlString(EControlTypes control_type, U32 index) +{ + return getStringFromKeyData(mControlsMap[control_type].getKeyData(index)); +} + +void LLKeyConflictHandler::loadFromSettings(const LLViewerKeyboard::KeyMode& keymode, control_map_t *destination) +{ + for (LLInitParam::ParamIterator::const_iterator it = keymode.bindings.begin(), + end_it = keymode.bindings.end(); + it != end_it; + ++it) + { + KEY key; + MASK mask; + if (it->key.getValue().empty()) + { + key = KEY_NONE; + } + else + { + LLKeyboard::keyFromString(it->key, &key); + } + LLKeyboard::maskFromString(it->mask, &mask); + std::string command_name = it->command; + // it->command + // It might be better to have map, but at the moment enum is easier to iterate through. + // Besides keys.xml might not contain all commands + control_enum_t::const_iterator iter = command_to_key.find(command_name); + if (iter != command_to_key.end()) + { + LLKeyConflict &type_data = (*destination)[iter->second]; + type_data.mAssignable = true; + // Don't care about conflict level, all movement and view commands already account for it + type_data.mKeyBind.addKeyData(CLICK_NONE, key, mask); + } + } +} + +void LLKeyConflictHandler::loadFromSettings(const EModes &load_mode, const std::string &filename, control_map_t *destination) +{ + if (filename.empty()) + { + return; + } + + LLViewerKeyboard::Keys keys; + LLSimpleXUIParser parser; + + if (parser.readXUI(filename, keys) + && keys.validateBlock()) + { + switch (load_mode) + { + case MODE_FIRST_PERSON: + if (keys.first_person.isProvided()) + { + loadFromSettings(keys.first_person, destination); + } + break; + case MODE_THIRD_PERSON: + if (keys.third_person.isProvided()) + { + loadFromSettings(keys.third_person, destination); + } + break; + case MODE_EDIT: + if (keys.edit.isProvided()) + { + loadFromSettings(keys.edit, destination); + } + break; + case MODE_EDIT_AVATAR: + if (keys.edit_avatar.isProvided()) + { + loadFromSettings(keys.edit_avatar, destination); + } + break; + case MODE_SITTING: + if (keys.sitting.isProvided()) + { + loadFromSettings(keys.sitting, destination); + } + break; + default: + break; + } + } +} + +void LLKeyConflictHandler::loadFromSettings(EModes load_mode) +{ + mControlsMap.clear(); + mDefaultsMap.clear(); + if (load_mode == MODE_GENERAL) + { + for (U32 i = 0; i < CONTROL_NUM_INDICES; i++) + { + EControlTypes type = (EControlTypes)i; + switch (type) + { + case LLKeyConflictHandler::CONTROL_VIEW_ACTIONS: + case LLKeyConflictHandler::CONTROL_INTERACTIONS: + case LLKeyConflictHandler::CONTROL_MOVEMENTS: + case LLKeyConflictHandler::CONTROL_MEDIACONTENT: + case LLKeyConflictHandler::CONTROL_CAMERA: + case LLKeyConflictHandler::CONTROL_EDIT_TITLE: + case LLKeyConflictHandler::CONTROL_RESERVED: + // ignore 'headers', they are for representation and organization purposes + break; + default: + { + std::string name = getControlName(type); + LLControlVariablePtr var = gSavedSettings.getControl(name); + if (var) + { + LLKeyBind bind(var->getValue()); + LLKeyConflict key(bind, true, 0); + mControlsMap[type] = key; + } + break; + } + } + } + } + else + { + // load defaults + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "keys.xml"); + loadFromSettings(load_mode, filename, &mDefaultsMap); + + // load user's + filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "keys.xml"); + if (gDirUtilp->fileExists(filename)) + { + loadFromSettings(load_mode, filename, &mControlsMap); + } + else + { + mControlsMap = mDefaultsMap; + } + } + mLoadedMode = load_mode; + + generatePlaceholders(); +} + +void LLKeyConflictHandler::saveToSettings() +{ + if (mControlsMap.empty()) + { + return; + } + + if (mLoadedMode == MODE_GENERAL) + { + for (U32 i = 0; i < CONTROL_NUM_INDICES; i++) + { + EControlTypes type = (EControlTypes)i; + switch (type) + { + case LLKeyConflictHandler::CONTROL_VIEW_ACTIONS: + case LLKeyConflictHandler::CONTROL_INTERACTIONS: + case LLKeyConflictHandler::CONTROL_MOVEMENTS: + case LLKeyConflictHandler::CONTROL_MEDIACONTENT: + case LLKeyConflictHandler::CONTROL_CAMERA: + case LLKeyConflictHandler::CONTROL_EDIT_TITLE: + case LLKeyConflictHandler::CONTROL_RESERVED: + // ignore 'headers', they are for representation and organization purposes + break; + default: + { + if (mControlsMap[type].mAssignable) + { + std::string name = getControlName(type); + if (gSavedSettings.controlExists(name)) + { + gSavedSettings.setLLSD(name, mControlsMap[type].mKeyBind.asLLSD()); + } + else if (!mControlsMap[type].mKeyBind.empty()) + { + // shouldn't happen user side since all settings are supposed to be declared already, but handy when creating new ones + // (just don't forget to change comment and to copy them from user's folder) + LL_INFOS() << "Creating new keybinding " << name << LL_ENDL; + gSavedSettings.declareLLSD(name, mControlsMap[type].mKeyBind.asLLSD(), "comment", LLControlVariable::PERSIST_ALWAYS); + } + } + break; + } + } + } + } + else + { + // loaded full copy of original file + std::string filename = gDirUtilp->findFile("keys.xml", + gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""), + gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + + LLViewerKeyboard::Keys keys; + LLSimpleXUIParser parser; + + if (parser.readXUI(filename, keys) + && keys.validateBlock()) + { + // replace category we edited + + // todo: fix this + // workaround to avoid doing own param container + LLViewerKeyboard::KeyMode mode; + LLViewerKeyboard::KeyBinding binding; + + control_map_t::iterator iter = mControlsMap.begin(); + control_map_t::iterator end = mControlsMap.end(); + for (; iter != end; ++iter) + { + U32 size = iter->second.mKeyBind.getDataCount(); + for (U32 i = 0; i < size; ++i) + { + // Still write empty keys to make sure we will maintain UI position + LLKeyData data = iter->second.mKeyBind.getKeyData(i); + if (data.mKey == KEY_NONE) + { + binding.key = ""; + } + else + { + // Note: this is UI string, we might want to hardcode our own for 'fixed' use in keys.xml + binding.key = LLKeyboard::stringFromKey(data.mKey); + } + binding.mask = string_from_mask(data.mMask); + binding.command = getControlName(iter->first); + mode.bindings.add(binding); + } + } + + switch (mLoadedMode) + { + case MODE_FIRST_PERSON: + if (keys.first_person.isProvided()) + { + keys.first_person.bindings.set(mode.bindings, true); + } + break; + case MODE_THIRD_PERSON: + if (keys.third_person.isProvided()) + { + keys.third_person.bindings.set(mode.bindings, true); + } + break; + case MODE_EDIT: + if (keys.edit.isProvided()) + { + keys.edit.bindings.set(mode.bindings, true); + } + break; + case MODE_EDIT_AVATAR: + if (keys.edit_avatar.isProvided()) + { + keys.edit_avatar.bindings.set(mode.bindings, true); + } + break; + case MODE_SITTING: + if (keys.sitting.isProvided()) + { + keys.sitting.bindings.set(mode.bindings, true); + } + break; + default: + break; + } + + // write back to user's xml; + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "keys.xml"); + + LLXMLNodePtr output_node = new LLXMLNode("keys", false); + LLXUIParser parser; + parser.writeXUI(output_node, keys); + + // Write the resulting XML to file + if (!output_node->isNull()) + { + LLFILE *fp = LLFile::fopen(filename, "w"); + if (fp != NULL) + { + LLXMLNode::writeHeaderToFile(fp); + output_node->writeToFile(fp); + fclose(fp); + } + } + // Now force a rebind for keyboard + if (gDirUtilp->fileExists(filename)) + { + gViewerKeyboard.loadBindingsXML(filename); + } + } + } + mHasUnsavedChanges = false; +} + +LLKeyData LLKeyConflictHandler::getDefaultControl(EControlTypes control_type, U32 index) +{ + if (mLoadedMode == MODE_GENERAL) + { + std::string name = getControlName(control_type); + LLControlVariablePtr var = gSavedSettings.getControl(name); + if (var) + { + return LLKeyBind(var->getDefault()).getKeyData(index); + } + return LLKeyData(); + } + else + { + control_map_t::iterator iter = mDefaultsMap.find(control_type); + if (iter != mDefaultsMap.end()) + { + return iter->second.mKeyBind.getKeyData(index); + } + return LLKeyData(); + } +} + +void LLKeyConflictHandler::resetToDefault(EControlTypes control_type, U32 index) +{ + LLKeyData data = getDefaultControl(control_type, index); + mControlsMap[control_type].setKeyData(data, index); +} + +void LLKeyConflictHandler::resetToDefault(EControlTypes control_type) +{ + if (mLoadedMode == MODE_GENERAL) + { + std::string name = getControlName(control_type); + LLControlVariablePtr var = gSavedSettings.getControl(name); + if (var) + { + mControlsMap[control_type].mKeyBind = LLKeyBind(var->getDefault()); + } + else + { + mControlsMap[control_type].mKeyBind.clear(); + } + } + else + { + control_map_t::iterator iter = mDefaultsMap.find(control_type); + if (iter != mDefaultsMap.end()) + { + mControlsMap[control_type].mKeyBind = iter->second.mKeyBind; + } + else + { + mControlsMap[control_type].mKeyBind.clear(); + } + } +} + +void LLKeyConflictHandler::resetToDefaults(EModes mode) +{ + if (mode == MODE_GENERAL) + { + for (U32 i = 0; i < CONTROL_NUM_INDICES; i++) + { + EControlTypes type = (EControlTypes)i; + switch (type) + { + case LLKeyConflictHandler::CONTROL_VIEW_ACTIONS: + case LLKeyConflictHandler::CONTROL_INTERACTIONS: + case LLKeyConflictHandler::CONTROL_MOVEMENTS: + case LLKeyConflictHandler::CONTROL_MEDIACONTENT: + case LLKeyConflictHandler::CONTROL_CAMERA: + case LLKeyConflictHandler::CONTROL_EDIT_TITLE: + case LLKeyConflictHandler::CONTROL_RESERVED: + // ignore 'headers', they are for representation and organization purposes + break; + default: + { + resetToDefault(type); + break; + } + } + } + } + else + { + mControlsMap.clear(); + mControlsMap = mDefaultsMap; + generatePlaceholders(); + } + + mHasUnsavedChanges = true; +} + +void LLKeyConflictHandler::resetToDefaults() +{ + if (!empty()) + { + resetToDefaults(mLoadedMode); + } +} + +void LLKeyConflictHandler::resetAllToDefaults() +{ + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "keys.xml"); + if (gDirUtilp->fileExists(filename)) + { + LLFile::remove(filename); + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "keys.xml"); + gViewerKeyboard.loadBindingsXML(filename); + } + + for (U32 i = 0; i < CONTROL_NUM_INDICES; i++) + { + EControlTypes type = (EControlTypes)i; + switch (type) + { + case LLKeyConflictHandler::CONTROL_VIEW_ACTIONS: + case LLKeyConflictHandler::CONTROL_INTERACTIONS: + case LLKeyConflictHandler::CONTROL_MOVEMENTS: + case LLKeyConflictHandler::CONTROL_MEDIACONTENT: + case LLKeyConflictHandler::CONTROL_RESERVED: + // ignore 'headers', they are for representation and organization purposes + break; + default: + { + resetToDefault(type); + break; + } + } + } + mHasUnsavedChanges = false; +} + +void LLKeyConflictHandler::clear() +{ + mHasUnsavedChanges = false; + mControlsMap.clear(); + mDefaultsMap.clear(); +} + +void LLKeyConflictHandler::resetKeyboardBindings() +{ + std::string filename = gDirUtilp->findFile("keys.xml", + gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""), + gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + + gViewerKeyboard.loadBindingsXML(filename); +} + +void LLKeyConflictHandler::generatePlaceholders() +{ + +} + +void LLKeyConflictHandler::registerTemporaryControl(EControlTypes control_type, EMouseClickType mouse, KEY key, MASK mask, U32 conflict_mask) +{ + LLKeyConflict *type_data = &mControlsMap[control_type]; + type_data->mAssignable = false; + type_data->mConflictMask = conflict_mask; + type_data->mKeyBind.addKeyData(mouse, key, mask); +} + diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h new file mode 100644 index 0000000000..79bd9b8438 --- /dev/null +++ b/indra/newview/llkeyconflict.h @@ -0,0 +1,214 @@ +/** + * @file llkeyconflict.h + * @brief + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2019, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLKEYCONFLICT_H +#define LL_LLKEYCONFLICT_H + +#include "llkeybind.h" +#include "llviewerkeyboard.h" + + +class LLKeyConflict +{ +public: + LLKeyConflict() : mAssignable(true), mConflictMask(0) {} //temporary assignable, don't forget to change once all keys are recorded + LLKeyConflict(bool assignable, U32 conflict_mask) + : mAssignable(assignable), mConflictMask(conflict_mask) {} + LLKeyConflict(const LLKeyBind &bind, bool assignable, U32 conflict_mask) + : mAssignable(assignable), mConflictMask(conflict_mask), mKeyBind(bind) {} + + LLKeyData getPrimaryKeyData() { return mKeyBind.getKeyData(0); } + LLKeyData getKeyData(U32 index) { return mKeyBind.getKeyData(index); } + void setPrimaryKeyData(const LLKeyData& data) { mKeyBind.replaceKeyData(data, 0); } + void setKeyData(const LLKeyData& data, U32 index) { mKeyBind.replaceKeyData(data, index); } + bool canHandle(EMouseClickType mouse, KEY key, MASK mask) { return mKeyBind.canHandle(mouse, key, mask); } + + LLKeyBind mKeyBind; + bool mAssignable; // whether user can change key or key simply acts as placeholder + U32 mConflictMask; +}; + +class LLKeyConflictHandler +{ +public: + + enum EModes // partially repeats e_keyboard_mode + { + MODE_FIRST_PERSON, + MODE_THIRD_PERSON, + MODE_EDIT, + MODE_EDIT_AVATAR, + MODE_SITTING, + MODE_GENERAL, + MODE_COUNT + }; + + enum EConflictTypes // priority higherst to lowest + { + CONFLICT_LAND = 1, + CONFLICT_OBJECT = 2, + CONFLICT_TOUCH = 4, + CONFLICT_INTERACTIBLE = 8, + CONFLICT_AVATAR = 16, + CONFLICT_ANY = 511 + }; + + // todo, unfortunately will have to remove this and use map/array of strings + enum EControlTypes + { + CONTROL_VIEW_ACTIONS = 0, // Group control, for visual representation in view, not for use + CONTROL_ABOUT, + CONTROL_ORBIT, + CONTROL_PAN, + CONTROL_WORLD_MAP, + CONTROL_ZOOM, + CONTROL_INTERACTIONS, // Group control, for visual representation + CONTROL_BUILD, + //CONTROL_DRAG, + CONTROL_EDIT, + //CONTROL_MENU, + CONTROL_OPEN, + CONTROL_TOUCH, + CONTROL_WEAR, + CONTROL_MOVEMENTS, // Group control, for visual representation + CONTROL_MOVETO, + CONTROL_SIT, + CONTROL_TELEPORTTO, + CONTROL_FORWARD, + CONTROL_BACKWARD, + CONTROL_LEFT, // Check and sinc name with real movement names + CONTROL_RIGHT, + CONTROL_LSTRAFE, + CONTROL_RSTRAFE, + CONTROL_JUMP, + CONTROL_DOWN, + //CONTROL_RUN, + CONTROL_TOGGLE_RUN, + CONTROL_TOGGLE_FLY, + CONTROL_STOP, + CONTROL_CAMERA, // Group control, for visual representation + CONTROL_LOOK_UP, + CONTROL_LOOK_DOWN, + CONTROL_CAMERA_FORWARD, + CONTROL_CAMERA_BACKWARD, + CONTROL_CAMERA_FFORWARD, + CONTROL_CAMERA_FBACKWARD, + CONTROL_CAMERA_FSITTING, + CONTROL_CAMERA_BSITTING, + CONTROL_CAMERA_SOVER, + CONTROL_CAMERA_SUNDER, + CONTROL_CAMERA_SOVER_SITTING, + CONTROL_CAMERA_SUNDER_SITTING, + CONTROL_CAMERA_PANUP, + CONTROL_CAMERA_PANDOWN, + CONTROL_CAMERA_PANLEFT, + CONTROL_CAMERA_PANRIGHT, + CONTROL_CAMERA_PANIN, + CONTROL_CAMERA_PANOUT, + CONTROL_CAMERA_SPIN_CCW, + CONTROL_CAMERA_SPIN_CW, + CONTROL_CAMERA_SPIN_CCW_SITTING, + CONTROL_CAMERA_SPIN_CW_SITTING, + CONTROL_EDIT_TITLE, // Group control, for visual representation + CONTROL_EDIT_AV_SPIN_CCW, + CONTROL_EDIT_AV_SPIN_CW, + CONTROL_EDIT_AV_SPIN_OVER, + CONTROL_EDIT_AV_SPIN_UNDER, + CONTROL_EDIT_AV_MV_FORWARD, + CONTROL_EDIT_AV_MV_BACKWARD, + CONTROL_MEDIACONTENT, // Group control, for visual representation + CONTROL_PARCEL, // Play pause + CONTROL_MEDIA, // Play stop + CONTROL_VOICE, // Keep pressing for it to be ON + CONTROL_TOGGLE_VOICE, // Press once to ON/OFF + CONTROL_START_CHAT, // Press once to ON/OFF + CONTROL_START_GESTURE, // Press once to ON/OFF + CONTROL_RESERVED, // Special group control, controls that are disabled by default and not meant to be changed + CONTROL_DELETE, + CONTROL_RESERVED_MENU, + CONTROL_RESERVED_SELECT, + CONTROL_SHIFT_SELECT, + CONTROL_CNTRL_SELECT, + CONTROL_NUM_INDICES // Size, always should be last + }; + + // Note: missed selection and edition commands (would be really nice to go through selection via MB4/5 or wheel) + + LLKeyConflictHandler(); + LLKeyConflictHandler(EModes mode); + + bool canHandleControl(EControlTypes control_type, EMouseClickType mouse_ind, KEY key, MASK mask); + bool canHandleKey(EControlTypes control_type, KEY key, MASK mask); + bool canHandleMouse(EControlTypes control_type, EMouseClickType mouse_ind, MASK mask); + bool canHandleMouse(EControlTypes control_type, S32 mouse_ind, MASK mask); //Just for convinience + bool canAssignControl(EControlTypes control_type); + void registerControl(EControlTypes control_type, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask); //todo: return conflicts? + + LLKeyData getControl(EControlTypes control_type, U32 data_index); + + static std::string LLKeyConflictHandler::getStringFromKeyData(const LLKeyData& keydata); + static std::string getControlName(EControlTypes control_type); + std::string getControlString(EControlTypes control_type, U32 data_index); + + + // Drops any changes loads controls with ones from 'saved settings' or from xml + void loadFromSettings(EModes load_mode); + // Saves settings to 'saved settings' or to xml + void saveToSettings(); + + LLKeyData getDefaultControl(EControlTypes control_type, U32 data_index); + // Resets keybinding to default variant from 'saved settings' or xml + void resetToDefault(EControlTypes control_type, U32 index); + void resetToDefault(EControlTypes control_type); + void resetToDefaults(EModes mode); + void resetToDefaults(); + void resetAllToDefaults(); + + bool empty() { return mControlsMap.empty(); } + void clear(); + + bool hasUnsavedChanges() { return mHasUnsavedChanges; } + EModes getLoadedMode() { return mLoadedMode; } + // todo: conflict search + +private: + // at the moment these kind of control is not savable, but takes part will take part in conflict resolution + void registerTemporaryControl(EControlTypes control_type, EMouseClickType mouse_ind, KEY key, MASK mask, U32 conflict_mask); + + typedef std::map control_map_t; + void loadFromSettings(const LLViewerKeyboard::KeyMode& keymode, control_map_t *destination); + void loadFromSettings(const EModes &load_mode, const std::string &filename, control_map_t *destination); + void resetKeyboardBindings(); + void generatePlaceholders(); //'headers' for ui and non-assignable values + + control_map_t mControlsMap; + control_map_t mDefaultsMap; + bool mHasUnsavedChanges; + EModes mLoadedMode; +}; + + +#endif // LL_LLKEYCONFLICT_H diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp index a14041717f..878810e0dd 100644 --- a/indra/newview/llviewerkeyboard.cpp +++ b/indra/newview/llviewerkeyboard.cpp @@ -603,6 +603,12 @@ void start_gesture( EKeystate s ) } } +void toggle_parcel_media(EKeystate s) +{ + bool pause = LLViewerMedia::isAnyMediaPlaying(); + LLViewerMedia::setAllMediaPaused(pause); +} + #define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, ACTION); REGISTER_KEYBOARD_ACTION("jump", agent_jump); REGISTER_KEYBOARD_ACTION("push_down", agent_push_down); @@ -644,6 +650,7 @@ REGISTER_KEYBOARD_ACTION("edit_avatar_move_backward", edit_avatar_move_backward) REGISTER_KEYBOARD_ACTION("stop_moving", stop_moving); REGISTER_KEYBOARD_ACTION("start_chat", start_chat); REGISTER_KEYBOARD_ACTION("start_gesture", start_gesture); +REGISTER_KEYBOARD_ACTION("toggle_parcel_media", toggle_parcel_media); #undef REGISTER_KEYBOARD_ACTION LLViewerKeyboard::LLViewerKeyboard() @@ -805,7 +812,7 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c mBindings[mode][index].mFunction = function; if (index == mBindingCount[mode]) - mBindingCount[mode]++; + mBindingCount[mode]++; return TRUE; } @@ -816,21 +823,25 @@ LLViewerKeyboard::KeyBinding::KeyBinding() command("command") {} -LLViewerKeyboard::KeyMode::KeyMode(EKeyboardMode _mode) -: bindings("binding"), - mode(_mode) +LLViewerKeyboard::KeyMode::KeyMode() +: bindings("binding") {} LLViewerKeyboard::Keys::Keys() -: first_person("first_person", KeyMode(MODE_FIRST_PERSON)), - third_person("third_person", KeyMode(MODE_THIRD_PERSON)), - edit("edit", KeyMode(MODE_EDIT)), - sitting("sitting", KeyMode(MODE_SITTING)), - edit_avatar("edit_avatar", KeyMode(MODE_EDIT_AVATAR)) +: first_person("first_person"), + third_person("third_person"), + edit("edit"), + sitting("sitting"), + edit_avatar("edit_avatar") {} S32 LLViewerKeyboard::loadBindingsXML(const std::string& filename) { + for (S32 i = 0; i < MODE_COUNT; i++) + { + mBindingCount[i] = 0; + } + S32 binding_count = 0; Keys keys; LLSimpleXUIParser parser; @@ -838,16 +849,16 @@ S32 LLViewerKeyboard::loadBindingsXML(const std::string& filename) if (parser.readXUI(filename, keys) && keys.validateBlock()) { - binding_count += loadBindingMode(keys.first_person); - binding_count += loadBindingMode(keys.third_person); - binding_count += loadBindingMode(keys.edit); - binding_count += loadBindingMode(keys.sitting); - binding_count += loadBindingMode(keys.edit_avatar); + binding_count += loadBindingMode(keys.first_person, MODE_FIRST_PERSON); + binding_count += loadBindingMode(keys.third_person, MODE_THIRD_PERSON); + binding_count += loadBindingMode(keys.edit, MODE_EDIT); + binding_count += loadBindingMode(keys.sitting, MODE_SITTING); + binding_count += loadBindingMode(keys.edit_avatar, MODE_EDIT_AVATAR); } return binding_count; } -S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode) +S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode, S32 mode) { S32 binding_count = 0; for (LLInitParam::ParamIterator::const_iterator it = keymode.bindings.begin(), @@ -855,12 +866,15 @@ S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode) it != end_it; ++it) { - KEY key; - MASK mask; - LLKeyboard::keyFromString(it->key, &key); - LLKeyboard::maskFromString(it->mask, &mask); - bindKey(keymode.mode, key, mask, it->command); - binding_count++; + if (!it->key.getValue().empty()) + { + KEY key; + MASK mask; + LLKeyboard::keyFromString(it->key, &key); + LLKeyboard::maskFromString(it->mask, &mask); + bindKey(mode, key, mask, it->command); + binding_count++; + } } return binding_count; diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h index 110dc89d28..2bfe285be4 100644 --- a/indra/newview/llviewerkeyboard.h +++ b/indra/newview/llviewerkeyboard.h @@ -71,8 +71,8 @@ public: struct KeyMode : public LLInitParam::Block { Multiple bindings; - EKeyboardMode mode; - KeyMode(EKeyboardMode mode); + + KeyMode(); }; struct Keys : public LLInitParam::Block @@ -100,7 +100,7 @@ public: void scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level); private: - S32 loadBindingMode(const LLViewerKeyboard::KeyMode& keymode); + S32 loadBindingMode(const LLViewerKeyboard::KeyMode& keymode, S32 mode); BOOL bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name); // Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 676f06bcb9..fcca081647 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -35,7 +35,6 @@ #include "llnotificationsutil.h" #include "llsdserialize.h" #include "llui.h" -#include "llkeybindings.h" #include "llkeyboard.h" #include "llagent.h" @@ -691,33 +690,38 @@ void LLVoiceClient::keyDown(KEY key, MASK mask) return; } - if (LLAgent::isActionAllowed("speak") && gControlBindings.canHandleKey(LLControlBindings::CONTROL_VOICE, key, mask)) + // + /*static LLCachedControl key_bind(gSavedSettings, "control_toggle_voice"); + LLKeyBind bind(key_bind); + if (LLAgent::isActionAllowed("speak") && bind().canHandleKey(key, mask)) { bool down = gKeyboard->getKeyDown(mPTTKey); if (down) { inputUserControlState(down); } - } + }*/ } void LLVoiceClient::keyUp(KEY key, MASK mask) { - if (gControlBindings.canHandleKey(LLControlBindings::CONTROL_VOICE, key, mask)) + /*static LLCachedControl key_bind(gSavedSettings, "control_toggle_voice"); + if (key_bind().canHandleKey(key, mask)) { bool down = gKeyboard->getKeyDown(mPTTKey); if (!down) { inputUserControlState(down); } - } + }*/ } void LLVoiceClient::updateMouseState(S32 click, MASK mask, bool down) { - if(LLAgent::isActionAllowed("speak") && gControlBindings.canHandleMouse(LLControlBindings::CONTROL_VOICE, click, mask)) + /*static LLCachedControl mouse_bind(gSavedSettings, "control_toggle_voice"); + if (mouse_bind().canHandleMouse((EMouseClickType)click, mask)) { inputUserControlState(down); - } + }*/ } diff --git a/indra/newview/skins/default/xui/en/floater_select_key.xml b/indra/newview/skins/default/xui/en/floater_select_key.xml index 4e89df5a73..c00b805954 100644 --- a/indra/newview/skins/default/xui/en/floater_select_key.xml +++ b/indra/newview/skins/default/xui/en/floater_select_key.xml @@ -7,7 +7,15 @@ height="90" layout="topleft" name="modal container" - width="240"> + width="272"> + + Keyboard + + + Mouse Buttons + - Press a key to set your Speak button trigger. + width="212"> +Press a key to set your trigger. +Allowed input: [INPUT]. + +