From c0ed4b6ff5301a7c90b32e3f552f84b84ee80465 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
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(-)

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 <andreykproductengine@lindenlab.com>
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(-)

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<LLUUID> 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 4d7c106a6108ff88b5b5211addc5e8b7506fb1b1 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Thu, 19 Sep 2019 16:57:22 +0300
Subject: SL-6109 New cell type with icon and text (and 1 pixel offset for all
 text cells)

---
 indra/llui/llscrolllistcell.cpp | 146 +++++++++++++++++++++++++++++++++++++++-
 indra/llui/llscrolllistcell.h   |  29 +++++++-
 2 files changed, 169 insertions(+), 6 deletions(-)

diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp
index 8000efad0e..63762ab8b8 100644
--- a/indra/llui/llscrolllistcell.cpp
+++ b/indra/llui/llscrolllistcell.cpp
@@ -50,6 +50,10 @@ LLScrollListCell* LLScrollListCell::create(const LLScrollListCell::Params& cell_
 	{
 		cell = new LLScrollListDate(cell_p);
 	}
+	else if (cell_p.type() == "icontext")
+	{
+		cell = new LLScrollListIconText(cell_p);
+	}
 	else	// default is "text"
 	{
 		cell = new LLScrollListText(cell_p);
@@ -168,7 +172,7 @@ U32 LLScrollListText::sCount = 0;
 
 LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p)
 :	LLScrollListCell(p),
-	mText(p.value().asString()),
+	mText(p.text.isProvided() ? p.text() : p.value().asString()),
 	mFont(p.font),
 	mColor(p.color),
 	mUseColor(p.color.isProvided()),
@@ -296,7 +300,7 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col
 		switch(mFontAlignment)
 		{
 		case LLFontGL::LEFT:
-			left = mFont->getWidth(mText.getString(), 0, mHighlightOffset);
+			left = mFont->getWidth(mText.getString(), 1, mHighlightOffset);
 			break;
 		case LLFontGL::RIGHT:
 			left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX);
@@ -319,7 +323,7 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col
 	switch(mFontAlignment)
 	{
 	case LLFontGL::LEFT:
-		start_x = 0.f;
+		start_x = 1.f;
 		break;
 	case LLFontGL::RIGHT:
 		start_x = (F32)getWidth();
@@ -435,3 +439,139 @@ const LLSD LLScrollListDate::getValue() const
 {
 	return mDate;
 }
+
+//
+// LLScrollListIconText
+//
+LLScrollListIconText::LLScrollListIconText(const LLScrollListCell::Params& p)
+    : LLScrollListText(p),
+    mIcon(p.value().isUUID() ? LLUI::getUIImageByID(p.value().asUUID()) : LLUI::getUIImage(p.value().asString())),
+    mPad(4)
+{
+    mTextWidth = getWidth() - mPad /*padding*/ - mFont->getLineHeight();
+}
+
+LLScrollListIconText::~LLScrollListIconText()
+{
+}
+
+const LLSD LLScrollListIconText::getValue() const
+{
+    if (mIcon.isNull())
+    {
+        return LLStringUtil::null;
+    }
+    return mIcon->getName();
+}
+
+void LLScrollListIconText::setValue(const LLSD& value)
+{
+    if (value.isUUID())
+    {
+        // don't use default image specified by LLUUID::null, use no image in that case
+        LLUUID image_id = value.asUUID();
+        mIcon = image_id.notNull() ? LLUI::getUIImageByID(image_id) : LLUIImagePtr(NULL);
+    }
+    else
+    {
+        std::string value_string = value.asString();
+        if (LLUUID::validate(value_string))
+        {
+            setValue(LLUUID(value_string));
+        }
+        else if (!value_string.empty())
+        {
+            mIcon = LLUI::getUIImage(value.asString());
+        }
+        else
+        {
+            mIcon = NULL;
+        }
+    }
+}
+
+void LLScrollListIconText::setWidth(S32 width)
+{
+    LLScrollListCell::setWidth(width);
+    // Assume that iamge height and width is identical to font height and width
+    mTextWidth = width - mPad /*padding*/ - mFont->getLineHeight();
+}
+
+
+void LLScrollListIconText::draw(const LLColor4& color, const LLColor4& highlight_color)	 const
+{
+    LLColor4 display_color;
+    if (mUseColor)
+    {
+        display_color = mColor;
+    }
+    else
+    {
+        display_color = color;
+    }
+
+    S32 icon_height = mFont->getLineHeight();
+    S32 icon_space = mIcon ? (icon_height + mPad) : 0;
+
+    if (mHighlightCount > 0)
+    {
+        S32 left = 0;
+        switch (mFontAlignment)
+        {
+        case LLFontGL::LEFT:
+            left = mFont->getWidth(mText.getString(), icon_space + 1, mHighlightOffset);
+            break;
+        case LLFontGL::RIGHT:
+            left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX) - icon_space;
+            break;
+        case LLFontGL::HCENTER:
+            left = (getWidth() - mFont->getWidth(mText.getString()) - icon_space) / 2;
+            break;
+        }
+        LLRect highlight_rect(left - 2,
+            mFont->getLineHeight() + 1,
+            left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1,
+            1);
+        mRoundedRectImage->draw(highlight_rect, highlight_color);
+    }
+
+    // Try to draw the entire string
+    F32 right_x;
+    U32 string_chars = mText.length();
+    F32 start_text_x = 0.f;
+    S32 start_icon_x = 0;
+    switch (mFontAlignment)
+    {
+    case LLFontGL::LEFT:
+        start_text_x = icon_space + 1;
+        start_icon_x = 1;
+        break;
+    case LLFontGL::RIGHT:
+        start_text_x = (F32)getWidth();
+        start_icon_x = getWidth() - mFont->getWidth(mText.getString()) - icon_space;
+        break;
+    case LLFontGL::HCENTER:
+        F32 center = (F32)getWidth()* 0.5f;
+        start_text_x = center + ((F32)icon_space * 0.5f);
+        start_icon_x = center - (((F32)icon_space + mFont->getWidth(mText.getString())) * 0.5f);
+        break;
+    }
+    mFont->render(mText.getWString(), 0,
+        start_text_x, 0.f,
+        display_color,
+        mFontAlignment,
+        LLFontGL::BOTTOM,
+        0,
+        LLFontGL::NO_SHADOW,
+        string_chars,
+        getTextWidth(),
+        &right_x,
+        TRUE);
+
+    if (mIcon)
+    {
+        mIcon->draw(start_icon_x, 0, icon_height, icon_height, mColor);
+    }
+}
+
+
diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h
index d625ebddcc..1604a9b1dc 100644
--- a/indra/llui/llscrolllistcell.h
+++ b/indra/llui/llscrolllistcell.h
@@ -59,7 +59,8 @@ public:
 									visible;
 
 		Optional<void*>				userdata;
-		Optional<LLSD>				value;
+		Optional<LLSD>				value; // state of checkbox, icon id/name, date
+		Optional<std::string>		text; // description or text
 		Optional<std::string>		tool_tip;
 
 		Optional<const LLFontGL*>	font;
@@ -152,7 +153,7 @@ public:
 	void			setText(const LLStringExplicit& text);
 	void			setFontStyle(const U8 font_style);
 
-private:
+protected:
 	LLUIString		mText;
 	S32				mTextWidth;
 	const LLFontGL*	mFont;
@@ -169,7 +170,7 @@ private:
 };
 
 /*
- * Cell displaying an image.
+ * Cell displaying an image. AT the moment, this is specifically UI image
  */
 class LLScrollListIcon : public LLScrollListCell
 {
@@ -223,4 +224,26 @@ private:
 	LLDate		mDate;
 };
 
+/*
+* Cell displaying icon and text.
+*/
+
+class LLScrollListIconText : public LLScrollListText
+{
+public:
+    LLScrollListIconText(const LLScrollListCell::Params& p);
+    /*virtual*/ ~LLScrollListIconText();
+    /*virtual*/ void	draw(const LLColor4& color, const LLColor4& highlight_color) const;
+    /*virtual*/ const LLSD		getValue() const;
+    /*virtual*/ void	setValue(const LLSD& value);
+
+
+    S32					getIconWidth() const;
+    /*virtual*/ void	setWidth(S32 width);/* { LLScrollListCell::setWidth(width); mTextWidth = width - ; }*/
+
+private:
+    LLPointer<LLUIImage>	mIcon;
+    S32						mPad;
+};
+
 #endif
-- 
cgit v1.2.3


From fc238f6ca06b6fc71ed3bb7c3968f48406bb2c09 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Thu, 19 Sep 2019 16:59:23 +0300
Subject: SL-6109 Extended Key-to-string functionality

---
 indra/llui/llmenugl.cpp       | 10 +++---
 indra/llui/llmenugl.h         | 13 ++++++--
 indra/llwindow/llkeyboard.cpp | 77 +++++++++++++++++++++++--------------------
 indra/llwindow/llkeyboard.h   | 14 ++------
 4 files changed, 60 insertions(+), 54 deletions(-)

diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 676c94468f..e6a3de281e 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -263,13 +263,13 @@ BOOL LLMenuItemGL::handleRightMouseUp(S32 x, S32 y, MASK mask)
 
 // This function checks to see if the accelerator key is already in use;
 // if not, it will be added to the list
-BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLKeyBinding*> *listp)
+BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp)
 {
-	LLKeyBinding *accelerator = NULL;
+	LLMenuKeyboardBinding *accelerator = NULL;
 
 	if (mAcceleratorKey != KEY_NONE)
 	{
-		std::list<LLKeyBinding*>::iterator list_it;
+		std::list<LLMenuKeyboardBinding*>::iterator list_it;
 		for (list_it = listp->begin(); list_it != listp->end(); ++list_it)
 		{
 			accelerator = *list_it;
@@ -293,7 +293,7 @@ BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLKeyBinding*> *listp)
 		}
 		if (!accelerator)
 		{				
-			accelerator = new LLKeyBinding;
+			accelerator = new LLMenuKeyboardBinding;
 			if (accelerator)
 			{
 				accelerator->mKey = mAcceleratorKey;
@@ -1024,7 +1024,7 @@ BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask)
 
 // This function checks to see if the accelerator key is already in use;
 // if not, it will be added to the list
-BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list<LLKeyBinding*> *listp)
+BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp)
 {
 	LLMenuGL* branch = getBranch();
 	if (!branch)
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 78f688642e..3a6b849e73 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -42,6 +42,13 @@
 extern S32 MENU_BAR_HEIGHT;
 extern S32 MENU_BAR_WIDTH;
 
+class LLMenuKeyboardBinding
+{
+public:
+    KEY				mKey;
+    MASK			mMask;
+};
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLMenuItemGL
 //
@@ -109,7 +116,7 @@ public:
 	virtual void setBriefItem(BOOL brief);
 	virtual BOOL isBriefItem() const;
 
-	virtual BOOL addToAcceleratorList(std::list<LLKeyBinding*> *listp);
+	virtual BOOL addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp);
 	void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; }
 	BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; }
 
@@ -628,7 +635,7 @@ public:
 	virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
 
 	// check if we've used these accelerators already
-	virtual BOOL addToAcceleratorList(std::list <LLKeyBinding*> *listp);
+	virtual BOOL addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp);
 
 	// called to rebuild the draw label
 	virtual void buildDrawLabel( void );
@@ -794,7 +801,7 @@ private:
 
 	void checkMenuTrigger();
 
-	std::list <LLKeyBinding*>	mAccelerators;
+	std::list <LLMenuKeyboardBinding*>	mAccelerators;
 	BOOL						mAltKeyTrigger;
 };
 
diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp
index f6f6c3931c..8e75325859 100644
--- a/indra/llwindow/llkeyboard.cpp
+++ b/indra/llwindow/llkeyboard.cpp
@@ -347,7 +347,48 @@ std::string LLKeyboard::stringFromKey(KEY key)
 	return res;
 }
 
+//static
+std::string LLKeyboard::stringFromAccelerator(MASK accel_mask)
+{
+    std::string res;
+
+    LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator;
 
+    if (trans == NULL)
+    {
+        LL_ERRS() << "No mKeyStringTranslator" << LL_ENDL;
+        return res;
+    }
+
+    // Append any masks
+#ifdef LL_DARWIN
+    // Standard Mac names for modifier keys in menu equivalents
+    // We could use the symbol characters, but they only exist in certain fonts.
+    if (accel_mask & MASK_CONTROL)
+    {
+        if (accel_mask & MASK_MAC_CONTROL)
+        {
+            res.append(trans("accel-mac-control"));
+        }
+        else
+        {
+            res.append(trans("accel-mac-command"));		// Symbol would be "\xE2\x8C\x98"
+        }
+    }
+    if (accel_mask & MASK_ALT)
+        res.append(trans("accel-mac-option"));		// Symbol would be "\xE2\x8C\xA5"
+    if (accel_mask & MASK_SHIFT)
+        res.append(trans("accel-mac-shift"));		// Symbol would be "\xE2\x8C\xA7"
+#else
+    if (accel_mask & MASK_CONTROL)
+        res.append(trans("accel-win-control"));
+    if (accel_mask & MASK_ALT)
+        res.append(trans("accel-win-alt"));
+    if (accel_mask & MASK_SHIFT)
+        res.append(trans("accel-win-shift"));
+#endif
+    return res;
+}
 //static
 std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key )
 {
@@ -359,41 +400,7 @@ std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key )
 		return res;
 	}
 	
-	LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator;
-	
-	if( trans == NULL )
-	{
-		LL_ERRS() << "No mKeyStringTranslator" << LL_ENDL;
-		return res;
-	}
-	
-	// Append any masks
-#ifdef LL_DARWIN
-	// Standard Mac names for modifier keys in menu equivalents
-	// We could use the symbol characters, but they only exist in certain fonts.
-	if( accel_mask & MASK_CONTROL )
-	{
-		if ( accel_mask & MASK_MAC_CONTROL )
-		{
-			res.append( trans("accel-mac-control") );
-		}
-		else
-		{
-			res.append( trans("accel-mac-command") );		// Symbol would be "\xE2\x8C\x98"
-		}
-	}
-	if( accel_mask & MASK_ALT )
-		res.append( trans("accel-mac-option") );		// Symbol would be "\xE2\x8C\xA5"
-	if( accel_mask & MASK_SHIFT )
-		res.append( trans("accel-mac-shift") );		// Symbol would be "\xE2\x8C\xA7"
-#else
-	if( accel_mask & MASK_CONTROL )
-		res.append( trans("accel-win-control") );
-	if( accel_mask & MASK_ALT )
-		res.append( trans("accel-win-alt") );
-	if( accel_mask & MASK_SHIFT )
-		res.append( trans("accel-win-shift") );
-#endif
+	res.append(stringFromAccelerator(accel_mask));
 	std::string key_string = LLKeyboard::stringFromKey(key);
 	if ((accel_mask & MASK_NORMALKEYS) &&
 		(key_string[0] == '-' || key_string[0] == '=' || key_string[0] == '+'))
diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h
index 6f2dc87317..f6404164e7 100644
--- a/indra/llwindow/llkeyboard.h
+++ b/indra/llwindow/llkeyboard.h
@@ -38,10 +38,10 @@ enum EKeystate
 {
 	KEYSTATE_DOWN,
 	KEYSTATE_LEVEL,
-	KEYSTATE_UP 
+	KEYSTATE_UP
 };
 
-typedef boost::function<void(EKeystate keystate)> LLKeyFunc;
+typedef boost::function<bool(EKeystate keystate)> LLKeyFunc;
 typedef std::string (LLKeyStringTranslatorFunc)(const char *label);
 	
 enum EKeyboardInsertMode
@@ -50,15 +50,6 @@ enum EKeyboardInsertMode
 	LL_KIM_OVERWRITE
 };
 
-class LLKeyBinding
-{
-public:
-	KEY				mKey;
-	MASK			mMask;
-// 	const char		*mName; // unused
-	LLKeyFunc		mFunction;
-};
-
 class LLWindowCallbacks;
 
 class LLKeyboard
@@ -104,6 +95,7 @@ public:
 	static BOOL		maskFromString(const std::string& str, MASK *mask);		// False on failure
 	static BOOL		keyFromString(const std::string& str, KEY *key);			// False on failure
 	static std::string stringFromKey(KEY key);
+	static std::string stringFromAccelerator( MASK accel_mask ); // separated for convinience, returns with "+": "Shift+" or "Shift+Alt+"...
 	static std::string stringFromAccelerator( MASK accel_mask, KEY key );
 
 	void setCallbacks(LLWindowCallbacks *cbs) { mCallbacks = cbs; }
-- 
cgit v1.2.3


From dcb1bea0f6086d963fba8b374d0294223bf66a11 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Thu, 19 Sep 2019 16:55:28 +0300
Subject: SL-6109 Implement keybindings

---
 indra/llcommon/CMakeLists.txt         |   2 +
 indra/llcommon/indra_constants.h      |  10 +++
 indra/llcommon/llkeybind.cpp          | 147 ++++++++++++++++++++++++++++++++++
 indra/llcommon/llkeybind.h            |  70 ++++++++++++++++
 indra/llwindow/llmousehandler.cpp     |   2 +-
 indra/llwindow/llmousehandler.h       |  12 +--
 indra/llxml/CMakeLists.txt            |   1 -
 indra/llxml/llcontrol.h               |   2 -
 indra/llxml/llcontrolgroupreader.h    |  80 ------------------
 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 +-
 19 files changed, 268 insertions(+), 133 deletions(-)
 create mode 100644 indra/llcommon/llkeybind.cpp
 create mode 100644 indra/llcommon/llkeybind.h
 delete mode 100644 indra/llxml/llcontrolgroupreader.h

diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index af41b9e460..7e52a620db 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -73,6 +73,7 @@ set(llcommon_SOURCE_FILES
     llinitparam.cpp
     llinitdestroyclass.cpp
     llinstancetracker.cpp
+    llkeybind.cpp
     llleap.cpp
     llleaplistener.cpp
     llliveappconfig.cpp
@@ -183,6 +184,7 @@ set(llcommon_HEADER_FILES
     llinitdestroyclass.h
     llinitparam.h
     llinstancetracker.h
+    llkeybind.h
     llkeythrottle.h
     llleap.h
     llleaplistener.h
diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h
index 0fbf4b966b..e763d413e5 100644
--- a/indra/llcommon/indra_constants.h
+++ b/indra/llcommon/indra_constants.h
@@ -54,6 +54,16 @@ enum ETerrainBrushType
 	E_LANDBRUSH_INVALID = 6
 };
 
+enum EMouseClickType{
+    CLICK_NONE = -1,
+    CLICK_LEFT = 0,
+    CLICK_MIDDLE,
+    CLICK_RIGHT,
+    CLICK_BUTTON4,
+    CLICK_BUTTON5,
+    CLICK_DOUBLELEFT
+};
+
 // keys
 // Bit masks for various keyboard modifier keys.
 const MASK MASK_NONE =			0x0000;
diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp
new file mode 100644
index 0000000000..f227c0a1a5
--- /dev/null
+++ b/indra/llcommon/llkeybind.cpp
@@ -0,0 +1,147 @@
+/** 
+ * @file llkeybind.cpp
+ * @brief Information about key combinations.
+ *
+ * $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$
+ */
+
+#include "linden_common.h"
+
+#include "llkeybind.h"
+
+#include "llsd.h"
+#include "llsdutil.h"
+
+LLKeyData::LLKeyData()
+    : mMouse(CLICK_NONE), mKey(KEY_NONE), mMask(MASK_NONE)
+{
+}
+
+LLKeyData::LLKeyData(const LLSD &key_data)
+{
+    mMouse = (EMouseClickType)key_data["mouse"].asInteger();
+    mKey = key_data["key"].asInteger();
+    mMask = key_data["mask"].asInteger();
+}
+
+LLSD LLKeyData::asLLSD() const
+{
+    LLSD data;
+    data["mouse"] = (LLSD::Integer)mMouse;
+    data["key"] = (LLSD::Integer)mKey;
+    data["mask"] = (LLSD::Integer)mMask;
+    return data;
+}
+
+bool LLKeyData::isEmpty() const
+{
+    return mMouse == CLICK_NONE && mKey == KEY_NONE &&  mMask == MASK_NONE;
+}
+
+void LLKeyData::reset()
+{
+    mMouse = CLICK_NONE;
+    mKey = KEY_NONE;
+    mMask = MASK_NONE;
+}
+
+LLKeyData& LLKeyData::operator=(const LLKeyData& rhs)
+{
+    mMouse = rhs.mMouse;
+    mKey = rhs.mKey;
+    mMask = rhs.mMask;
+    return *this;
+}
+
+// LLKeyBind
+
+LLKeyBind::LLKeyBind(const LLSD &key_bind)
+{
+    if (key_bind.has("DataPrimary"))
+    {
+        mDataPrimary = LLKeyData(key_bind["DataPrimary"]);
+    }
+    if (key_bind.has("DataSecondary"))
+    {
+        mDataSecondary = LLKeyData(key_bind["DataSecondary"]);
+    }
+}
+
+bool LLKeyBind::operator==(const LLKeyBind& rhs)
+{
+    if (mDataPrimary.mMouse != rhs.mDataPrimary.mMouse) return false;
+    if (mDataPrimary.mKey != rhs.mDataPrimary.mKey) return false;
+    if (mDataPrimary.mMask != rhs.mDataPrimary.mMask) return false;
+    if (mDataSecondary.mMouse != rhs.mDataSecondary.mMouse) return false;
+    if (mDataSecondary.mKey != rhs.mDataSecondary.mKey) return false;
+    if (mDataSecondary.mMask != rhs.mDataSecondary.mMask) return false;
+    return true;
+}
+
+bool LLKeyBind::empty()
+{
+    if (mDataPrimary.mMouse != CLICK_NONE) return false;
+    if (mDataPrimary.mKey != KEY_NONE) return false;
+    if (mDataPrimary.mMask != MASK_NONE) return false;
+    if (mDataSecondary.mMouse != CLICK_NONE) return false;
+    if (mDataSecondary.mKey != KEY_NONE) return false;
+    if (mDataSecondary.mMask != MASK_NONE) return false;
+    return false;
+}
+
+LLSD LLKeyBind::asLLSD() const
+{
+    LLSD data;
+    if (!mDataPrimary.isEmpty())
+    {
+        data["DataPrimary"] = mDataPrimary.asLLSD();
+    }
+    if (!mDataSecondary.isEmpty())
+    {
+        data["DataSecondary"] = mDataSecondary.asLLSD();
+    }
+    return data;
+}
+
+bool LLKeyBind::canHandle(EMouseClickType mouse, KEY key, MASK mask) const
+{
+    if (mDataPrimary.mKey == key && mDataPrimary.mMask == mask && mDataPrimary.mMouse == mouse)
+    {
+        return true;
+    }
+    if (mDataSecondary.mKey == key && mDataSecondary.mMask == mask && mDataSecondary.mMouse == mouse)
+    {
+        return true;
+    }
+    return false;
+}
+
+bool LLKeyBind::canHandleKey(KEY key, MASK mask) const
+{
+    return canHandle(CLICK_NONE, key, mask);
+}
+
+bool LLKeyBind::canHandleMouse(EMouseClickType mouse, MASK mask) const
+{
+    return canHandle(mouse, KEY_NONE, mask);
+}
+
diff --git a/indra/llcommon/llkeybind.h b/indra/llcommon/llkeybind.h
new file mode 100644
index 0000000000..4fe622fb79
--- /dev/null
+++ b/indra/llcommon/llkeybind.h
@@ -0,0 +1,70 @@
+/** 
+ * @file llkeybind.h
+ * @brief Information about key combinations.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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_KEYBIND_H
+#define LL_KEYBIND_H
+
+#include "indra_constants.h"
+
+// KeyData - single key combination (mouse/mask/keyboard)
+class LL_COMMON_API LLKeyData
+{
+public:
+    LLKeyData();
+    LLKeyData(const LLSD &key_data);
+
+    LLSD asLLSD() const;
+    bool isEmpty() const;
+    void reset();
+    LLKeyData& operator=(const LLKeyData& rhs);
+
+    EMouseClickType mMouse;
+    KEY mKey;
+    MASK mMask;
+};
+
+// One function can bind to multiple Key options
+class LLKeyBind
+{
+public:
+    LLKeyBind() {}
+    LLKeyBind(const LLSD &key_bind);
+
+    bool operator==(const LLKeyBind& rhs);
+    bool empty();
+
+    LLSD asLLSD() const;
+
+    bool canHandle(EMouseClickType mouse, KEY key, MASK mask) const;
+    bool canHandleKey(KEY key, MASK mask) const;
+    bool canHandleMouse(EMouseClickType mouse, MASK mask) const;
+
+    LLKeyData mDataPrimary;
+    LLKeyData mDataSecondary;
+};
+
+
+#endif // LL_KEYBIND_H
diff --git a/indra/llwindow/llmousehandler.cpp b/indra/llwindow/llmousehandler.cpp
index d5fa65fe4b..e41ebd42f3 100644
--- a/indra/llwindow/llmousehandler.cpp
+++ b/indra/llwindow/llmousehandler.cpp
@@ -27,7 +27,7 @@
 #include "llmousehandler.h"
 
 //virtual
-BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down)
+BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down)
 {
 	BOOL handled = FALSE;
 	if (down)
diff --git a/indra/llwindow/llmousehandler.h b/indra/llwindow/llmousehandler.h
index 1dcd0348d8..d221dd117c 100644
--- a/indra/llwindow/llmousehandler.h
+++ b/indra/llwindow/llmousehandler.h
@@ -29,6 +29,7 @@
 
 #include "linden_common.h"
 #include "llrect.h"
+#include "indra_constants.h"
 
 // Mostly-abstract interface.
 // Intended for use via multiple inheritance. 
@@ -46,16 +47,7 @@ public:
 		SHOW_ALWAYS,
 	} EShowToolTip;
 
-	typedef enum {
-		CLICK_LEFT,
-		CLICK_MIDDLE,
-		CLICK_RIGHT,
-		CLICK_BUTTON4,
-		CLICK_BUTTON5,
-		CLICK_DOUBLELEFT
-	} EClickType;
-
-	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) = 0;
 	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask) = 0;
 	virtual BOOL	handleMiddleMouseDown(S32 x, S32 y, MASK mask) = 0;
diff --git a/indra/llxml/CMakeLists.txt b/indra/llxml/CMakeLists.txt
index 17400a203e..013a422d35 100644
--- a/indra/llxml/CMakeLists.txt
+++ b/indra/llxml/CMakeLists.txt
@@ -28,7 +28,6 @@ set(llxml_HEADER_FILES
     CMakeLists.txt
 
     llcontrol.h
-    llcontrolgroupreader.h
     llxmlnode.h
     llxmlparser.h
     llxmltree.h
diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index de0d366492..9312bbc91a 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -34,8 +34,6 @@
 #include "llrefcount.h"
 #include "llinstancetracker.h"
 
-#include "llcontrolgroupreader.h"
-
 #include <vector>
 
 // *NOTE: boost::visit_each<> generates warning 4675 on .net 2003
diff --git a/indra/llxml/llcontrolgroupreader.h b/indra/llxml/llcontrolgroupreader.h
deleted file mode 100644
index 6a27a65499..0000000000
--- a/indra/llxml/llcontrolgroupreader.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/** 
- * @file llcontrolgroupreader.h
- * @brief Interface providing readonly access to LLControlGroup (intended for unit testing)
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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_LLCONTROLGROUPREADER_H
-#define LL_LLCONTROLGROUPREADER_H
-
-#include "stdtypes.h"
-#include <string>
-
-#include "v3math.h"
-#include "v3dmath.h"
-#include "v3color.h"
-#include "v4color.h"
-#include "llrect.h"
-
-class LLControlGroupReader
-{
-public:
-	LLControlGroupReader() {}
-	virtual ~LLControlGroupReader() {}
-
-	virtual std::string getString(const std::string& name) { return ""; }
-	virtual LLWString	getWString(const std::string& name) { return LLWString(); }
-	virtual std::string	getText(const std::string& name) { return ""; }
-	virtual LLVector3	getVector3(const std::string& name) { return LLVector3(); }
-	virtual LLVector3d	getVector3d(const std::string& name) { return LLVector3d(); }
-	virtual LLRect		getRect(const std::string& name) { return LLRect(); }
-	virtual BOOL		getBOOL(const std::string& name) { return FALSE; }
-	virtual S32			getS32(const std::string& name) { return 0; }
-	virtual F32			getF32(const std::string& name) {return 0.0f; }
-	virtual U32			getU32(const std::string& name) {return 0; }
-	virtual LLSD        getLLSD(const std::string& name) { return LLSD(); }
-
-	virtual LLColor4	getColor(const std::string& name) { return LLColor4(); }
-	virtual LLColor4	getColor4(const std::string& name) { return LLColor4(); }
-	virtual LLColor3	getColor3(const std::string& name) { return LLColor3(); }
-	
-	virtual void		setBOOL(const std::string& name, BOOL val) {}
-	virtual void		setS32(const std::string& name, S32 val) {}
-	virtual void		setF32(const std::string& name, F32 val) {}
-	virtual void		setU32(const std::string& name, U32 val) {}
-	virtual void		setString(const std::string&  name, const std::string& val) {}
-	virtual void		setVector3(const std::string& name, const LLVector3 &val) {}
-	virtual void		setVector3d(const std::string& name, const LLVector3d &val) {}
-	virtual void		setRect(const std::string& name, const LLRect &val) {}
-	virtual void		setColor4(const std::string& name, const LLColor4 &val) {}
-	virtual void    	setLLSD(const std::string& name, const LLSD& val) {}
-};
-
-#endif /* LL_LLCONTROLGROUPREADER_H */
-
-
-
-
-
-
-
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<LLUICtrl>("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<LLToolPie>
 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 <andreykproductengine@lindenlab.com>
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

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<LLGroupControlsListItem>
+{
+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<LLPanelPreferenceControls> 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<LLScrollListCtrl>("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<LLVoiceSetKeyDialog>("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" />
+        <panel
+         class="panel_preference_controls"
+         filename="panel_preferences_controls.xml"
+         label="Controls"
+         layout="topleft"
+         help_topic="preferences_controls_tab"
+         name="controls" />
     </tab_container>
 
 </floater>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<panel
+ border="true"
+ follows="all"
+ height="408"
+ label="Controls"
+ layout="topleft"
+ left="102"
+ name="controls"
+ top="1"
+ width="517">
+  <panel.string
+   name="control_view_actions">
+    View Actions
+  </panel.string>
+  <panel.string
+   name="control_about">
+    About/Profile
+  </panel.string>
+  <panel.string
+   name="control_orbit">
+    Orbit
+  </panel.string>
+  <panel.string
+   name="control_pan">
+    Pan
+  </panel.string>
+  <panel.string
+   name="control_world_map">
+    World Map
+  </panel.string>
+  <panel.string
+   name="control_zoom">
+    Zoom
+  </panel.string>
+  <panel.string
+   name="control_interactions">
+    Interactions
+  </panel.string>
+  <panel.string
+   name="control_build">
+    Build
+  </panel.string>
+  <panel.string
+   name="control_drag">
+    Drag
+  </panel.string>
+  <panel.string
+   name="control_edit">
+    Edit
+  </panel.string>
+  <panel.string
+   name="control_menu">
+    Menu
+  </panel.string>
+  <panel.string
+   name="control_open">
+    Open
+  </panel.string>
+  <panel.string
+   name="control_touch">
+    Touch
+  </panel.string>
+  <panel.string
+   name="control_wear">
+    Wear
+  </panel.string>
+  <panel.string
+   name="control_movements">
+    Move Actions
+  </panel.string>
+  <panel.string
+   name="control_moveto">
+    Move To
+  </panel.string>
+  <panel.string
+   name="control_sit">
+    Sit/Stand
+  </panel.string>
+  <panel.string
+   name="control_teleportto">
+    Teleport To
+  </panel.string>
+  <panel.string
+   name="control_forward">
+    Move Forward
+  </panel.string>
+  <panel.string
+   name="control_backward">
+    Move Backward
+  </panel.string>
+  <panel.string
+   name="control_left">
+    Left
+  </panel.string>
+  <panel.string
+   name="control_right">
+    Right
+  </panel.string>
+  <!--(check with move floater)-->
+  <panel.string
+   name="control_lstrafe">
+    Strafe left
+  </panel.string>
+  <panel.string
+   name="control_rstrafe">
+    Strafe right
+  </panel.string>
+  <panel.string
+   name="control_jump">
+    Strafe right
+  </panel.string>
+  <panel.string
+   name="control_down">
+    Strafe right
+  </panel.string>
+  <panel.string
+   name="control_run">
+    Run
+  </panel.string>
+  <panel.string
+   name="control_toggle_run">
+    Toggle Run
+  </panel.string>
+  <panel.string
+   name="control_fly">
+    Fly/Stop flying
+  </panel.string>
+  <panel.string
+   name="control_mediacontent">
+    Sound and Media
+  </panel.string>
+  <panel.string
+   name="control_parcel">
+    Play/Pause Parcel Media
+  </panel.string>
+  <panel.string
+   name="control_media">
+    Play/Stop All Media
+  </panel.string>
+  <panel.string
+   name="control_voice">
+    Voice
+  </panel.string>
+  <panel.string
+   name="control_toggle_voice">
+    Toggle Voice
+  </panel.string>
+  <panel.string
+   name="control_reserved">
+    Reserved Controls
+  </panel.string>
+  <!--
+   name="control_menu" not needed
+   -->
+  <panel.string
+   name="control_reserved_select">
+    Select
+  </panel.string>
+  <panel.string
+   name="control_shift_select">
+    Multi-Select
+  </panel.string>
+  <panel.string
+   name="control_cntrl_select">
+    Add to Selection
+  </panel.string>
+
+  <scroll_list
+   draw_heading="true"
+   follows="all"
+   layout="topleft"
+   column_padding="0"
+   top="3"
+   left="3"
+   bottom="-3"
+   right="-3"
+   multi_select="false"
+   name="controls_list">
+    <scroll_list.columns
+     relative_width="0.34"
+     label="Action"
+     name="lst_action" />
+    <scroll_list.columns
+     relative_width="0.33"
+     label="Primary Control Method"
+     name="lst_ctrl1" />
+    <scroll_list.columns
+     relative_width="0.33"
+     label="Secondary Control Method"
+     name="lst_ctrl2" />
+    <scroll_list.commit_callback
+      function="Pref.CommitControl" />
+  </scroll_list>
+
+</panel>
-- 
cgit v1.2.3


From c21812bf095de2defa4e61978b2659764c838abf Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Tue, 17 Sep 2019 21:36:59 +0300
Subject: SL-6109 Keyaboard support ready

---
 indra/llcommon/llkeybind.cpp                       | 180 ++++-
 indra/llcommon/llkeybind.h                         |  23 +-
 indra/llui/llscrolllistctrl.cpp                    |   4 +
 indra/llui/llscrolllistctrl.h                      |   4 +-
 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 ++++-
 14 files changed, 1798 insertions(+), 410 deletions(-)
 create mode 100644 indra/newview/llkeyconflict.cpp
 create mode 100644 indra/newview/llkeyconflict.h

diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp
index f227c0a1a5..765084bbf6 100644
--- a/indra/llcommon/llkeybind.cpp
+++ b/indra/llcommon/llkeybind.cpp
@@ -36,6 +36,11 @@ LLKeyData::LLKeyData()
 {
 }
 
+LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, MASK mask)
+: mMouse(mouse), mKey(key), mMask(mask)
+{
+}
+
 LLKeyData::LLKeyData(const LLSD &key_data)
 {
     mMouse = (EMouseClickType)key_data["mouse"].asInteger();
@@ -72,65 +77,100 @@ LLKeyData& LLKeyData::operator=(const LLKeyData& rhs)
     return *this;
 }
 
+bool LLKeyData::operator==(const LLKeyData& rhs)
+{
+    if (mMouse != rhs.mMouse) return false;
+    if (mKey != rhs.mKey) return false;
+    if (mMask != rhs.mMask) return false;
+    return true;
+}
+
+bool LLKeyData::operator!=(const LLKeyData& rhs)
+{
+    if (mMouse != rhs.mMouse) return true;
+    if (mKey != rhs.mKey) return true;
+    if (mMask != rhs.mMask) return true;
+    return false;
+}
+
 // LLKeyBind
 
 LLKeyBind::LLKeyBind(const LLSD &key_bind)
 {
-    if (key_bind.has("DataPrimary"))
-    {
-        mDataPrimary = LLKeyData(key_bind["DataPrimary"]);
-    }
-    if (key_bind.has("DataSecondary"))
+    if (key_bind.isArray())
     {
-        mDataSecondary = LLKeyData(key_bind["DataSecondary"]);
+        for (LLSD::array_const_iterator data = key_bind.beginArray(), endLists = key_bind.endArray();
+            data != endLists;
+            data++
+            )
+        {
+            mData.push_back(LLKeyData(*data));
+        }
     }
 }
 
 bool LLKeyBind::operator==(const LLKeyBind& rhs)
 {
-    if (mDataPrimary.mMouse != rhs.mDataPrimary.mMouse) return false;
-    if (mDataPrimary.mKey != rhs.mDataPrimary.mKey) return false;
-    if (mDataPrimary.mMask != rhs.mDataPrimary.mMask) return false;
-    if (mDataSecondary.mMouse != rhs.mDataSecondary.mMouse) return false;
-    if (mDataSecondary.mKey != rhs.mDataSecondary.mKey) return false;
-    if (mDataSecondary.mMask != rhs.mDataSecondary.mMask) return false;
+    U32 size = mData.size();
+    if (size != rhs.mData.size()) return false;
+
+    for (U32 i = 0; i < size; i++)
+    {
+        if (mData[i] != rhs.mData[i]) return false;
+    }
+
     return true;
 }
 
-bool LLKeyBind::empty()
+bool LLKeyBind::operator!=(const LLKeyBind& rhs)
 {
-    if (mDataPrimary.mMouse != CLICK_NONE) return false;
-    if (mDataPrimary.mKey != KEY_NONE) return false;
-    if (mDataPrimary.mMask != MASK_NONE) return false;
-    if (mDataSecondary.mMouse != CLICK_NONE) return false;
-    if (mDataSecondary.mKey != KEY_NONE) return false;
-    if (mDataSecondary.mMask != MASK_NONE) return false;
+    U32 size = mData.size();
+    if (size != rhs.mData.size()) return true;
+
+    for (U32 i = 0; i < size; i++)
+    {
+        if (mData[i] != rhs.mData[i]) return true;
+    }
+
     return false;
 }
 
-LLSD LLKeyBind::asLLSD() const
+bool LLKeyBind::isEmpty() const
 {
-    LLSD data;
-    if (!mDataPrimary.isEmpty())
+    for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
     {
-        data["DataPrimary"] = mDataPrimary.asLLSD();
+        if (!iter->isEmpty()) return false;
     }
-    if (!mDataSecondary.isEmpty())
+    return true;
+}
+
+LLSD LLKeyBind::asLLSD() const
+{
+    LLSD data;
+    for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
     {
-        data["DataSecondary"] = mDataSecondary.asLLSD();
+        if (!iter->isEmpty())
+        {
+            data.append(iter->asLLSD());
+        }
     }
     return data;
 }
 
 bool LLKeyBind::canHandle(EMouseClickType mouse, KEY key, MASK mask) const
 {
-    if (mDataPrimary.mKey == key && mDataPrimary.mMask == mask && mDataPrimary.mMouse == mouse)
+    if (mouse == CLICK_NONE && key == KEY_NONE)
     {
-        return true;
+        // assume placeholder
+        return false;
     }
-    if (mDataSecondary.mKey == key && mDataSecondary.mMask == mask && mDataSecondary.mMouse == mouse)
+
+    for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
     {
-        return true;
+        if (iter->mKey == key && iter->mMask == mask && iter->mMouse == mouse)
+        {
+            return true;
+        }
     }
     return false;
 }
@@ -145,3 +185,85 @@ bool LLKeyBind::canHandleMouse(EMouseClickType mouse, MASK mask) const
     return canHandle(mouse, KEY_NONE, mask);
 }
 
+bool LLKeyBind::addKeyData(EMouseClickType mouse, KEY key, MASK mask)
+{
+    if (!canHandle(mouse, key, mask))
+    {
+        mData.push_back(LLKeyData(mouse, key, mask));
+        return true;
+    }
+    return false;
+}
+
+bool LLKeyBind::addKeyData(const LLKeyData& data)
+{
+    if (!canHandle(data.mMouse, data.mKey, data.mMask))
+    {
+        mData.push_back(data);
+        return true;
+    }
+    return false;
+}
+
+void LLKeyBind::replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, U32 index)
+{
+    if (mouse != CLICK_NONE && key != KEY_NONE && mask != MASK_NONE)
+    {
+        for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
+        {
+            if (iter->mKey == key && iter->mMask == mask && iter->mMouse == mouse)
+            {
+                mData.erase(iter);
+                break;
+            }
+        }
+    }
+    if (mData.size() > index)
+    {
+        mData[index] = LLKeyData(mouse, key, mask);
+    }
+    else
+    {
+        mData.push_back(LLKeyData(mouse, key, mask));
+    }
+}
+
+void LLKeyBind::replaceKeyData(const LLKeyData& data, U32 index)
+{
+    for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
+    {
+        if (iter->mKey == data.mKey && iter->mMask == data.mMask && iter->mMouse == data.mMouse)
+        {
+            mData.erase(iter);
+            break;
+        }
+    }
+    if (mData.size() > index)
+    {
+        mData[index] = data;
+    }
+    else
+    {
+        mData.push_back(data);
+    }
+}
+
+bool LLKeyBind::hasKeyData(U32 index) const
+{
+    return mData.size() > index;
+}
+
+LLKeyData LLKeyBind::getKeyData(U32 index) const
+{
+    if (mData.size() > index)
+    {
+        return mData[index];
+    }
+    return LLKeyData();
+}
+
+U32 LLKeyBind::getDataCount()
+{
+    return mData.size();
+}
+
diff --git a/indra/llcommon/llkeybind.h b/indra/llcommon/llkeybind.h
index 4fe622fb79..481949f275 100644
--- a/indra/llcommon/llkeybind.h
+++ b/indra/llcommon/llkeybind.h
@@ -34,12 +34,16 @@ class LL_COMMON_API LLKeyData
 {
 public:
     LLKeyData();
+    LLKeyData(EMouseClickType mouse, KEY key, MASK mask);
     LLKeyData(const LLSD &key_data);
 
     LLSD asLLSD() const;
     bool isEmpty() const;
+    bool empty() const { return isEmpty(); };
     void reset();
     LLKeyData& operator=(const LLKeyData& rhs);
+    bool operator==(const LLKeyData& rhs);
+    bool operator!=(const LLKeyData& rhs);
 
     EMouseClickType mMouse;
     KEY mKey;
@@ -54,7 +58,9 @@ public:
     LLKeyBind(const LLSD &key_bind);
 
     bool operator==(const LLKeyBind& rhs);
-    bool empty();
+    bool operator!=(const LLKeyBind& rhs);
+    bool isEmpty() const;
+    bool empty() const { return isEmpty(); };
 
     LLSD asLLSD() const;
 
@@ -62,8 +68,19 @@ public:
     bool canHandleKey(KEY key, MASK mask) const;
     bool canHandleMouse(EMouseClickType mouse, MASK mask) const;
 
-    LLKeyData mDataPrimary;
-    LLKeyData mDataSecondary;
+    // these methods enshure there will be no repeats
+    bool addKeyData(EMouseClickType mouse, KEY key, MASK mask);
+    bool addKeyData(const LLKeyData& data);
+    void replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, U32 index);
+    void replaceKeyData(const LLKeyData& data, U32 index);
+    bool hasKeyData(U32 index) const;
+    void clear() { mData.clear(); };
+    LLKeyData getKeyData(U32 index) const;
+    U32 getDataCount();
+
+private:
+    typedef std::vector<LLKeyData> data_vector_t;
+    data_vector_t mData;
 };
 
 
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 6c8fde580f..7e17dd7c8d 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -130,6 +130,7 @@ LLScrollListCtrl::Params::Params()
 	search_column("search_column", 0),
 	sort_column("sort_column", -1),
 	sort_ascending("sort_ascending", true),
+	can_sort("can_sort", true),
 	mouse_wheel_opaque("mouse_wheel_opaque", false),
 	commit_on_keyboard_movement("commit_on_keyboard_movement", true),
 	heading_height("heading_height"),
@@ -165,6 +166,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
 	mSelectionChanged(false),
 	mNeedsScroll(false),
 	mCanSelect(true),
+	mCanSort(p.can_sort),
 	mColumnsDirty(false),
 	mMaxItemCount(INT_MAX), 
 	mBorderThickness( 2 ),
@@ -2801,6 +2803,8 @@ void LLScrollListCtrl::onClickColumn(void *userdata)
 	LLScrollListCtrl *parent = info->mParentCtrl;
 	if (!parent) return;
 
+	if (!parent->mCanSort) return;
+
 	S32 column_index = info->mIndex;
 
 	LLScrollListColumn* column = parent->mColumnsIndexed[info->mIndex];
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index d7572d9fcf..249d9a6f15 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -114,7 +114,8 @@ public:
 		// sort and search behavior
 		Optional<S32>	search_column,
 						sort_column;
-		Optional<bool>	sort_ascending;
+		Optional<bool>	sort_ascending,
+						can_sort; // whether user is allowed to sort
 
 		// colors
 		Optional<LLUIColor>	fg_unselected_color,
@@ -457,6 +458,7 @@ private:
 	bool			mNeedsScroll;
 	bool			mMouseWheelOpaque;
 	bool			mCanSelect;
+    bool			mCanSort;		// Whether user is allowed to sort
 	bool			mDisplayColumnHeaders;
 	bool			mColumnsDirty;
 	bool			mColumnWidthsDirty;
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<LabelTable>
     {}
 };
 
-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<LLUICtrl>("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<LLTextBase>("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<LLVoiceSetKeyDialog>);
+		LLFloaterReg::add("keybind_dialog", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLSetKeyBindDialog>);
 		registered_dialog = true;
 	}
 	
@@ -1754,53 +1784,6 @@ void LLFloaterPreference::onChangeQuality(const LLSD& data)
 
 void LLFloaterPreference::onClickSetKey()
 {
-	LLVoiceSetKeyDialog* dialog = LLFloaterReg::showTypedInstance<LLVoiceSetKeyDialog>("voice_set_key", LLSD(), TRUE);
-	if (dialog)
-	{
-		dialog->setParent(this);
-	}
-}
-
-void LLFloaterPreference::setKey(KEY key)
-{
-	getChild<LLUICtrl>("modifier_combo")->setValue(LLKeyboard::stringFromKey(key));
-	// update the control right away since we no longer wait for apply
-	getChild<LLUICtrl>("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<LLUICtrl>("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<LLPanel*>(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<LLCheckBoxCtrl>("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<LLScrollListCtrl>("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<LLPanelPreferenceControls> t_pref_contrls("panel_preference_controls");
 
-//-------------------For LLPanelPreferenceControls' list---------------------------
-class LLGroupControlsListItem : public LLScrollListItem, public LLHandleProvider<LLGroupControlsListItem>
+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<LLPanelPreferenceControls> 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<LLScrollListCtrl>("controls_list");
-    populateControlTable();
+    pKeyModeBox = getChild<LLComboBox>("key_mode");
 
     pControlsTable->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onListCommit, this));
+    pKeyModeBox->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onModeCommit, this));
+    getChild<LLButton>("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<LLSetKeyBindDialog>("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<LLVoiceSetKeyDialog>("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<std::string, LLKeyConflictHandler::EControlTypes> 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<EControlTypes, LLKeyConflict>::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<LLViewerKeyboard::KeyBinding>::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 <string,bind> 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<EControlTypes, LLKeyConflict> 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<KeyBinding>::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<KeyMode>
 	{
 		Multiple<KeyBinding>		bindings;
-		EKeyboardMode				mode;
-		KeyMode(EKeyboardMode mode);
+
+		KeyMode();
 	};
 
 	struct Keys : public LLInitParam::Block<Keys>
@@ -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<LLSD> 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<LLKeyBind> 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<LLKeyBind> 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">
+  <floater.string
+   name="keyboard">
+    Keyboard
+  </floater.string>
+  <floater.string
+   name="mouse">
+    Mouse Buttons
+  </floater.string>
     <text
      type="string"
      halign="center"
@@ -16,19 +24,35 @@
      height="30"
      layout="topleft"
      left="30"
-     name="Save item as:"
+     name="descritption"
      top="25"
      word_wrap="true"
-     width="180">
-        Press a key to set your Speak button trigger.
+     width="212">
+Press a key to set your trigger.
+Allowed input: [INPUT].
     </text>
+    <button
+     height="23"
+     label="Set Empty"
+     layout="topleft"
+     left="8"
+     name="SetEmpty"
+     top_pad="8"
+     width="80" />
+    <button
+     height="23"
+     label="Default"
+     layout="topleft"
+     left_pad="8"
+     name="Default"
+     top_delta="0"
+     width="80" />
     <button
      height="23"
      label="Cancel"
-     label_selected="Cancel"
      layout="topleft"
-     right="-10"
+     left_pad="8"
      name="Cancel"
-     top_pad="8"
-     width="100" />
+     top_delta="0"
+     width="80" />
 </floater>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
index a1a2fd0598..1bfee20c81 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
@@ -82,37 +82,37 @@
     Teleport To
   </panel.string>
   <panel.string
-   name="control_forward">
+   name="push_forward">
     Move Forward
   </panel.string>
   <panel.string
-   name="control_backward">
+   name="push_backward">
     Move Backward
   </panel.string>
   <panel.string
-   name="control_left">
+   name="turn_left">
     Left
   </panel.string>
   <panel.string
-   name="control_right">
+   name="turn_right">
     Right
   </panel.string>
   <!--(check with move floater)-->
   <panel.string
-   name="control_lstrafe">
+   name="slide_left">
     Strafe left
   </panel.string>
   <panel.string
-   name="control_rstrafe">
+   name="slide_right">
     Strafe right
   </panel.string>
   <panel.string
-   name="control_jump">
-    Strafe right
+   name="jump">
+    Jump/Up
   </panel.string>
   <panel.string
-   name="control_down">
-    Strafe right
+   name="push_down">
+    Down
   </panel.string>
   <panel.string
    name="control_run">
@@ -123,9 +123,85 @@
     Toggle Run
   </panel.string>
   <panel.string
-   name="control_fly">
+   name="toggle_fly">
     Fly/Stop flying
   </panel.string>
+  <panel.string
+   name="control_camera">
+    Camera
+  </panel.string>
+  <panel.string
+   name="look_up">
+    Look Up
+  </panel.string>
+  <panel.string
+   name="look_down">
+    Look Down
+  </panel.string>
+  <panel.string
+   name="move_forward">
+    Camera Forward
+  </panel.string>
+  <panel.string
+   name="move_backward">
+    Camera Backward
+  </panel.string>
+  <panel.string
+   name="move_forward_fast">
+    Camera Forward Fast
+  </panel.string>
+  <panel.string
+   name="move_backward_fast">
+    Camera Backward Fast
+  </panel.string>
+  <panel.string
+   name="move_forward_sitting">
+    Camera Forward Sitting
+  </panel.string>
+  <panel.string
+   name="move_backward_sitting">
+    Camera Backward Sitting
+  </panel.string>
+  <panel.string
+   name="spin_over">
+    Camera Spin Over
+  </panel.string>
+  <panel.string
+   name="spin_under">
+    Camera Spin Under
+  </panel.string>
+  <panel.string
+   name="spin_over_sitting">
+    Camera Spin Over
+  </panel.string>
+  <panel.string
+   name="spin_under_sitting">
+    Camera Spin Under
+  </panel.string>
+  <panel.string
+   name="pan_up">
+    Camera Pan Up
+  </panel.string>
+  <panel.string
+   name="pan_down">
+    Camera Pan Down
+  </panel.string>
+  <panel.string
+   name="pan_left">
+    Camera Pan Left
+  </panel.string>
+  <panel.string
+   name="pan_right">
+    Camera Pan Right
+  </panel.string>
+  <panel.string
+   name="pan_left">
+    Camera Pan In
+  </panel.string>
+  <panel.string
+   name="pan_right">
+    Camera Pan Out
+  </panel.string>
   <panel.string
    name="control_mediacontent">
     Sound and Media
@@ -150,6 +226,10 @@
    name="control_reserved">
     Reserved Controls
   </panel.string>
+  <panel.string
+   name="control_delete">
+    Delete
+  </panel.string>
   <!--
    name="control_menu" not needed
    -->
@@ -166,15 +246,60 @@
     Add to Selection
   </panel.string>
 
+  <combo_box
+   follows="top|left"
+   layout="topleft"
+   top="6"
+   left="10"
+   height="23"
+   width="110"
+   name="key_mode">
+    <combo_box.item
+     label="First Person "
+     name="first_person"
+     value="0"/>
+    <combo_box.item
+     label="Third Person "
+     name="third_person"
+     value="1"/>
+    <combo_box.item
+     label="Edit"
+     name="edit"
+     value="2"/>
+    <combo_box.item
+     label="Edit Avatar"
+     name="edit_avatar"
+     value="3"/>
+    <combo_box.item
+     label="Sitting"
+     name="sitting"
+     value="4"/>
+    <combo_box.item
+     label="General"
+     name="general"
+     value="5"/>
+  </combo_box>
+
+  <button
+   follows="top|left"
+   layout="topleft"
+   top="6"
+   right="-10"
+   height="23"
+   width="110"
+   label="Restore Default"
+   name="restore_defaults"/>
+  
   <scroll_list
    draw_heading="true"
    follows="all"
    layout="topleft"
    column_padding="0"
-   top="3"
+   top="31"
    left="3"
    bottom="-3"
    right="-3"
+   can_sort="false"
    multi_select="false"
    name="controls_list">
     <scroll_list.columns
@@ -182,13 +307,17 @@
      label="Action"
      name="lst_action" />
     <scroll_list.columns
-     relative_width="0.33"
-     label="Primary Control Method"
+     relative_width="0.22"
+     label="Control Method 1"
      name="lst_ctrl1" />
     <scroll_list.columns
-     relative_width="0.33"
-     label="Secondary Control Method"
+     relative_width="0.22"
+     label="Control Method 2"
      name="lst_ctrl2" />
+    <scroll_list.columns
+     relative_width="0.22"
+     label="Control Method 3"
+     name="lst_ctrl3" />
     <scroll_list.commit_callback
       function="Pref.CommitControl" />
   </scroll_list>
-- 
cgit v1.2.3


From 08969001e25397cc947b5aa027522d3cc7aa8c53 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Wed, 25 Sep 2019 17:54:36 +0300
Subject: SL-6109 Mouse support ready

---
 indra/llcommon/indra_constants.h                   |   3 +-
 indra/llcommon/llkeybind.cpp                       | 152 ++++++--
 indra/llcommon/llkeybind.h                         |  13 +-
 indra/llui/llscrolllistcell.cpp                    |   5 +
 indra/newview/llagent.cpp                          |  11 +
 indra/newview/llagent.h                            |   1 +
 indra/newview/llappviewer.cpp                      |   1 +
 indra/newview/llfloaterpreference.cpp              |  92 +++--
 indra/newview/llfloaterpreference.h                |   2 +-
 indra/newview/llkeyconflict.cpp                    | 131 ++++---
 indra/newview/llkeyconflict.h                      |  10 +-
 indra/newview/llviewerkeyboard.cpp                 | 424 ++++++++++++++++++---
 indra/newview/llviewerkeyboard.h                   |  82 +++-
 indra/newview/llviewerwindow.cpp                   |  68 ++--
 indra/newview/llviewerwindow.h                     |   3 +-
 .../skins/default/xui/en/floater_select_key.xml    |  16 +-
 .../default/xui/en/panel_preferences_controls.xml  |  10 +-
 17 files changed, 813 insertions(+), 211 deletions(-)

diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h
index e763d413e5..ef29e7e5cd 100644
--- a/indra/llcommon/indra_constants.h
+++ b/indra/llcommon/indra_constants.h
@@ -61,7 +61,8 @@ enum EMouseClickType{
     CLICK_RIGHT,
     CLICK_BUTTON4,
     CLICK_BUTTON5,
-    CLICK_DOUBLELEFT
+    CLICK_DOUBLELEFT,
+    CLICK_COUNT // 'size', CLICK_NONE does not counts
 };
 
 // keys
diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp
index 765084bbf6..0eca289d4b 100644
--- a/indra/llcommon/llkeybind.cpp
+++ b/indra/llcommon/llkeybind.cpp
@@ -32,20 +32,59 @@
 #include "llsdutil.h"
 
 LLKeyData::LLKeyData()
-    : mMouse(CLICK_NONE), mKey(KEY_NONE), mMask(MASK_NONE)
+    :
+    mMouse(CLICK_NONE),
+    mKey(KEY_NONE),
+    mMask(MASK_NONE),
+    mIgnoreMasks(false)
 {
 }
 
 LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, MASK mask)
-: mMouse(mouse), mKey(key), mMask(mask)
+    :
+    mMouse(mouse),
+    mKey(key),
+    mMask(mask),
+    mIgnoreMasks(false)
+{
+}
+
+LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, bool ignore_mask)
+    :
+    mMouse(mouse),
+    mKey(key),
+    mMask(MASK_NONE),
+    mIgnoreMasks(ignore_mask)
+{
+}
+
+LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask)
+    :
+    mMouse(mouse),
+    mKey(key),
+    mMask(mask),
+    mIgnoreMasks(ignore_mask)
 {
 }
 
 LLKeyData::LLKeyData(const LLSD &key_data)
 {
-    mMouse = (EMouseClickType)key_data["mouse"].asInteger();
-    mKey = key_data["key"].asInteger();
-    mMask = key_data["mask"].asInteger();
+    if (key_data.has("mouse"))
+    {
+        mMouse = (EMouseClickType)key_data["mouse"].asInteger();
+    }
+    if (key_data.has("key"))
+    {
+        mKey = key_data["key"].asInteger();
+    }
+    if (key_data.has("ignore_accelerators"))
+    {
+        mIgnoreMasks = key_data["ignore_accelerators"];
+    }
+    if (key_data.has("mask"))
+    {
+        mMask = key_data["mask"].asInteger();
+    }
 }
 
 LLSD LLKeyData::asLLSD() const
@@ -53,13 +92,20 @@ LLSD LLKeyData::asLLSD() const
     LLSD data;
     data["mouse"] = (LLSD::Integer)mMouse;
     data["key"] = (LLSD::Integer)mKey;
-    data["mask"] = (LLSD::Integer)mMask;
+    if (mIgnoreMasks)
+    {
+        data["ignore_accelerators"] = (LLSD::Boolean)mIgnoreMasks;
+    }
+    else
+    {
+        data["mask"] = (LLSD::Integer)mMask;
+    }
     return data;
 }
 
 bool LLKeyData::isEmpty() const
 {
-    return mMouse == CLICK_NONE && mKey == KEY_NONE &&  mMask == MASK_NONE;
+    return mMouse == CLICK_NONE && mKey == KEY_NONE;
 }
 
 void LLKeyData::reset()
@@ -67,6 +113,7 @@ void LLKeyData::reset()
     mMouse = CLICK_NONE;
     mKey = KEY_NONE;
     mMask = MASK_NONE;
+    mIgnoreMasks = false;
 }
 
 LLKeyData& LLKeyData::operator=(const LLKeyData& rhs)
@@ -74,6 +121,7 @@ LLKeyData& LLKeyData::operator=(const LLKeyData& rhs)
     mMouse = rhs.mMouse;
     mKey = rhs.mKey;
     mMask = rhs.mMask;
+    mIgnoreMasks = rhs.mIgnoreMasks;
     return *this;
 }
 
@@ -82,6 +130,7 @@ bool LLKeyData::operator==(const LLKeyData& rhs)
     if (mMouse != rhs.mMouse) return false;
     if (mKey != rhs.mKey) return false;
     if (mMask != rhs.mMask) return false;
+    if (mIgnoreMasks != rhs.mIgnoreMasks) return false;
     return true;
 }
 
@@ -90,6 +139,29 @@ bool LLKeyData::operator!=(const LLKeyData& rhs)
     if (mMouse != rhs.mMouse) return true;
     if (mKey != rhs.mKey) return true;
     if (mMask != rhs.mMask) return true;
+    if (mIgnoreMasks != rhs.mIgnoreMasks) return true;
+    return false;
+}
+
+bool LLKeyData::canHandle(const LLKeyData& data) const
+{
+    if (data.mKey == mKey
+        && data.mMouse == mMouse
+        && (mIgnoreMasks || data.mMask == mMask))
+    {
+        return true;
+    }
+    return false;
+}
+
+bool LLKeyData::canHandle(EMouseClickType mouse, KEY key, MASK mask) const
+{
+    if (mouse == mMouse
+        && key == mKey
+        && (mIgnoreMasks || mask == mMask))
+    {
+        return true;
+    }
     return false;
 }
 
@@ -167,7 +239,7 @@ bool LLKeyBind::canHandle(EMouseClickType mouse, KEY key, MASK mask) const
 
     for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
     {
-        if (iter->mKey == key && iter->mMask == mask && iter->mMouse == mouse)
+        if (iter->canHandle(mouse, key, mask))
         {
             return true;
         }
@@ -185,11 +257,34 @@ bool LLKeyBind::canHandleMouse(EMouseClickType mouse, MASK mask) const
     return canHandle(mouse, KEY_NONE, mask);
 }
 
-bool LLKeyBind::addKeyData(EMouseClickType mouse, KEY key, MASK mask)
+bool LLKeyBind::hasKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const
+{
+    if (mouse != CLICK_NONE || key != KEY_NONE)
+    {
+        for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
+        {
+            if (iter->mKey == key
+                && iter->mMask == mask
+                && iter->mMouse == mouse
+                && iter->mIgnoreMasks == ignore)
+            {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+bool LLKeyBind::hasKeyData(const LLKeyData& data) const
 {
-    if (!canHandle(mouse, key, mask))
+    return hasKeyData(data.mMouse, data.mKey, data.mMask, data.mIgnoreMasks);
+}
+
+bool LLKeyBind::addKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore)
+{
+    if (!hasKeyData(mouse, key, mask, ignore))
     {
-        mData.push_back(LLKeyData(mouse, key, mask));
+        mData.push_back(LLKeyData(mouse, key, mask, ignore));
         return true;
     }
     return false;
@@ -197,7 +292,7 @@ bool LLKeyBind::addKeyData(EMouseClickType mouse, KEY key, MASK mask)
 
 bool LLKeyBind::addKeyData(const LLKeyData& data)
 {
-    if (!canHandle(data.mMouse, data.mKey, data.mMask))
+    if (!hasKeyData(data))
     {
         mData.push_back(data);
         return true;
@@ -205,37 +300,48 @@ bool LLKeyBind::addKeyData(const LLKeyData& data)
     return false;
 }
 
-void LLKeyBind::replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, U32 index)
+void LLKeyBind::replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore, U32 index)
 {
-    if (mouse != CLICK_NONE && key != KEY_NONE && mask != MASK_NONE)
+    if (mouse != CLICK_NONE || key != KEY_NONE )
     {
-        for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
+        // if both click and key are none, we are inserting a placeholder, we don't want to reset anything
+        // otherwise reset identical key
+        for (data_vector_t::iterator iter = mData.begin(); iter != mData.end(); iter++)
         {
-            if (iter->mKey == key && iter->mMask == mask && iter->mMouse == mouse)
+            if (iter->mKey == key
+                && iter->mMouse == mouse
+                && iter->mIgnoreMasks == ignore
+                && (iter->mIgnoreMasks || iter->mMask == mask))
             {
-                mData.erase(iter);
+                iter->reset();
                 break;
             }
         }
     }
     if (mData.size() > index)
     {
-        mData[index] = LLKeyData(mouse, key, mask);
+        mData[index] = LLKeyData(mouse, key, mask, ignore);
     }
     else
     {
-        mData.push_back(LLKeyData(mouse, key, mask));
+        mData.push_back(LLKeyData(mouse, key, mask, ignore));
     }
 }
 
 void LLKeyBind::replaceKeyData(const LLKeyData& data, U32 index)
 {
-    for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
+    if (!data.isEmpty())
     {
-        if (iter->mKey == data.mKey && iter->mMask == data.mMask && iter->mMouse == data.mMouse)
+        for (data_vector_t::iterator iter = mData.begin(); iter != mData.end(); iter++)
         {
-            mData.erase(iter);
-            break;
+            if (iter->mKey == data.mKey
+                && iter->mMouse == data.mMouse
+                && iter->mIgnoreMasks == data.mIgnoreMasks
+                && (iter->mIgnoreMasks || iter->mMask == data.mMask))
+            {
+                iter->reset();
+                break;
+            }
         }
     }
     if (mData.size() > index)
diff --git a/indra/llcommon/llkeybind.h b/indra/llcommon/llkeybind.h
index 481949f275..25179a57f3 100644
--- a/indra/llcommon/llkeybind.h
+++ b/indra/llcommon/llkeybind.h
@@ -35,6 +35,8 @@ class LL_COMMON_API LLKeyData
 public:
     LLKeyData();
     LLKeyData(EMouseClickType mouse, KEY key, MASK mask);
+    LLKeyData(EMouseClickType mouse, KEY key, bool ignore_mask);
+    LLKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask);
     LLKeyData(const LLSD &key_data);
 
     LLSD asLLSD() const;
@@ -45,9 +47,13 @@ public:
     bool operator==(const LLKeyData& rhs);
     bool operator!=(const LLKeyData& rhs);
 
+    bool canHandle(const LLKeyData& data) const;
+    bool canHandle(EMouseClickType mouse, KEY key, MASK mask) const;
+
     EMouseClickType mMouse;
     KEY mKey;
     MASK mMask;
+    bool mIgnoreMasks;
 };
 
 // One function can bind to multiple Key options
@@ -68,10 +74,13 @@ public:
     bool canHandleKey(KEY key, MASK mask) const;
     bool canHandleMouse(EMouseClickType mouse, MASK mask) const;
 
+    bool LLKeyBind::hasKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const;
+    bool LLKeyBind::hasKeyData(const LLKeyData& data) const;
+
     // these methods enshure there will be no repeats
-    bool addKeyData(EMouseClickType mouse, KEY key, MASK mask);
+    bool addKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore);
     bool addKeyData(const LLKeyData& data);
-    void replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, U32 index);
+    void replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore, U32 index);
     void replaceKeyData(const LLKeyData& data, U32 index);
     bool hasKeyData(U32 index) const;
     void clear() { mData.clear(); };
diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp
index 63762ab8b8..0a33ee8878 100644
--- a/indra/llui/llscrolllistcell.cpp
+++ b/indra/llui/llscrolllistcell.cpp
@@ -314,6 +314,11 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col
 				left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1, 
 				1);
 		mRoundedRectImage->draw(highlight_rect, highlight_color);
+		/*LLRect highlight_rect(left - 2, 
+				mFont->getLineHeight() + 2, 
+				left + getWidth() + 2, 
+				1);
+		mRoundedRectImage->draw(highlight_rect, LLColor4::black);*/
 	}
 
 	// Try to draw the entire string
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index be90e623ad..0e43af91df 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -829,6 +829,17 @@ bool LLAgent::enableFlying()
 	return !sitting;
 }
 
+// static
+bool LLAgent::isSitting()
+{
+    BOOL sitting = FALSE;
+    if (isAgentAvatarValid())
+    {
+        sitting = gAgentAvatarp->isSitting();
+    }
+    return sitting;
+}
+
 void LLAgent::standUp()
 {
 	setControlFlags(AGENT_CONTROL_STAND_UP);
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index 5ba1083d8e..a5d37ef496 100644
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -343,6 +343,7 @@ public:
 	static void		toggleFlying();
 	static bool		enableFlying();
 	BOOL			canFly(); 			// Does this parcel allow you to fly?
+	static bool		isSitting();
 
 	//--------------------------------------------------------------------
 	// Voice
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index d3067456fa..dde7275e8e 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1451,6 +1451,7 @@ bool LLAppViewer::doFrame()
 			{
 				joystick->scanJoystick();
 				gKeyboard->scanKeyboard();
+                gViewerKeyboard.scanMouse();
 			}
 
 			// Update state based on messages, user input, object idle.
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 4a4f66db14..9c706a0d3a 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -166,7 +166,7 @@ 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 CAN_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
@@ -176,6 +176,7 @@ public:
 	~LLSetKeyBindDialog();
 
 	/*virtual*/ BOOL postBuild();
+	/*virtual*/ void onClose(bool app_quiting);
 
 	void setParent(LLPanelPreferenceControls* parent, U32 key_mask = DEFAULT_KEY_FILTER);
 
@@ -186,18 +187,23 @@ public:
 	static void onDefault(void* user_data);
 
 private:
-	LLPanelPreferenceControls* mParent;
+	LLPanelPreferenceControls* pParent;
+	LLCheckBoxCtrl* pCheckBox;
 
 	U32 mKeyMask;
 };
 
 LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key)
   : LLModalDialog(key),
-	mParent(NULL),
+	pParent(NULL),
 	mKeyMask(DEFAULT_KEY_FILTER)
 {
 }
 
+LLSetKeyBindDialog::~LLSetKeyBindDialog()
+{
+}
+
 //virtual
 BOOL LLSetKeyBindDialog::postBuild()
 {
@@ -205,15 +211,24 @@ BOOL LLSetKeyBindDialog::postBuild()
 	childSetAction("Default", onDefault, this);
 	childSetAction("Cancel", onCancel, this);
 	getChild<LLUICtrl>("Cancel")->setFocus(TRUE);
-	
+
+	pCheckBox = getChild<LLCheckBoxCtrl>("ignore_masks");
+
 	gFocusMgr.setKeystrokesOnly(TRUE);
 	
 	return TRUE;
 }
 
+//virtual
+void LLSetKeyBindDialog::onClose(bool app_quiting)
+{
+    pParent = NULL;
+    LLModalDialog::onClose(app_quiting);
+}
+
 void LLSetKeyBindDialog::setParent(LLPanelPreferenceControls* parent, U32 key_mask)
 {
-    mParent = parent;
+    pParent = parent;
     mKeyMask = key_mask;
 
     LLTextBase *text_ctrl = getChild<LLTextBase>("descritption");
@@ -232,10 +247,10 @@ void LLSetKeyBindDialog::setParent(LLPanelPreferenceControls* parent, U32 key_ma
         input += getString("keyboard");
     }
     text_ctrl->setTextArg("[INPUT]", input);
-}
 
-LLSetKeyBindDialog::~LLSetKeyBindDialog()
-{
+    bool can_ignore_masks = (key_mask & CAN_IGNORE_MASKS) != 0;
+    pCheckBox->setVisible(can_ignore_masks);
+    pCheckBox->setValue(false);
 }
 
 BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
@@ -249,10 +264,19 @@ BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
         return true;
     }
 
+    if (key == KEY_DELETE)
+    {
+        if (pParent)
+        {
+            pParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
+        }
+        closeFloater();
+        return true;
+    }
+
     // forbidden keys
     if (key == KEY_NONE
         || key == KEY_RETURN
-        || key == KEY_DELETE
         || key == KEY_BACKSPACE)
     {
         return false;
@@ -275,9 +299,9 @@ BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
         return false;
     }
 
-	else if (mParent)
+	if (pParent)
 	{
-		mParent->onSetKeyBind(CLICK_NONE, key, mask);
+        pParent->onSetKeyBind(CLICK_NONE, key, mask, pCheckBox->getValue().asBoolean());
 	}
 	closeFloater();
 	return result;
@@ -305,9 +329,9 @@ BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClic
         && (clicktype != CLICK_RIGHT || mask != 0) // reassigning menu button is not supported
         && ((mKeyMask & ALLOW_MASK_MOUSE) != 0 || mask == 0))
     {
-        if (mParent)
+        if (pParent)
         {
-            mParent->onSetKeyBind(clicktype, KEY_NONE, mask);
+            pParent->onSetKeyBind(clicktype, KEY_NONE, mask, pCheckBox->getValue().asBoolean());
         }
         result = TRUE;
         closeFloater();
@@ -333,9 +357,9 @@ void LLSetKeyBindDialog::onBlank(void* user_data)
 {
     LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
     // tmp needs 'no key' button
-    if (self->mParent)
+    if (self->pParent)
     {
-        self->mParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE);
+        self->pParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
     }
     self->closeFloater();
 }
@@ -345,9 +369,9 @@ void LLSetKeyBindDialog::onDefault(void* user_data)
 {
     LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
     // tmp needs 'no key' button
-    if (self->mParent)
+    if (self->pParent)
     {
-        self->mParent->onDefaultKeyBind();
+        self->pParent->onDefaultKeyBind();
     }
     self->closeFloater();
 }
@@ -2972,6 +2996,23 @@ BOOL LLPanelPreferenceControls::postBuild()
 // 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)
 {
+    /*S32 column = pControlsTable->getColumnIndexFromOffset(x);
+    LLScrollListItem* item = pControlsTable->hitItem(x, y);
+    static LLScrollListCell* last_cell = NULL;
+    if (item && column > 0)
+    {
+        LLScrollListCell* cell = item->getColumn(column);
+        if (cell)
+        {
+            cell->highlightText(0, CHAR_MAX);
+            if (last_cell != NULL && last_cell !=cell)
+            {
+                last_cell->highlightText(0, 0);
+            }
+            last_cell = cell;
+        }
+    }*/
+
     if (mShowKeyDialog)
     {
         if (mEditingIndex > 0 && mConflictHandler[mEditingMode].canAssignControl((LLKeyConflictHandler::EControlTypes)mEditingIndex))
@@ -2983,14 +3024,14 @@ BOOL LLPanelPreferenceControls::handleHover(S32 x, S32 y, MASK mask)
                 LLSetKeyBindDialog* dialog = LLFloaterReg::showTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD(), TRUE);
                 if (dialog)
                 {
-                    if (mConflictHandler[mEditingMode].getLoadedMode() == LLKeyConflictHandler::MODE_GENERAL)
-                    {
+                    /*if (mConflictHandler[mEditingMode].getLoadedMode() == LLKeyConflictHandler::MODE_GENERAL)
+                    {*/
                         dialog->setParent(this, DEFAULT_KEY_FILTER);
-                    }
+                    /*}
                     else
                     {
                         dialog->setParent(this, ALLOW_KEYS | ALLOW_MASK_KEYS);
-                    }
+                    }*/
                 }
             }
         }
@@ -3133,10 +3174,6 @@ void LLPanelPreferenceControls::populateControlTable()
             }
         }
     }
-
-    //temp
-    if (mEditingMode == LLKeyConflictHandler::MODE_GENERAL)
-        pControlsTable->setEnabled(false);
 }
 
 // Just a workaround to not care about first separator before headers (we can start from random header)
@@ -3226,7 +3263,8 @@ void LLPanelPreferenceControls::onModeCommit()
     regenerateControls();
 }
 
-void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask)
+// todo: copy onSetKeyBind to interface and inherit from interface
+void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore_mask)
 {
     LLKeyConflictHandler::EControlTypes control = (LLKeyConflictHandler::EControlTypes)mEditingIndex;
 
@@ -3241,7 +3279,7 @@ void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MAS
     if (item && mEditingColumn > 0)
     {
 
-        mConflictHandler[mEditingMode].registerControl(control, mEditingColumn - 1, click, key, mask);
+        mConflictHandler[mEditingMode].registerControl(control, mEditingColumn - 1, click, key, mask, ignore_mask);
 
         LLScrollListCell *cell = item->getColumn(1);
         cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 0));
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index bce84387ab..1ac0f076d2 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -310,7 +310,7 @@ public:
 
 	void onListCommit();
 	void onModeCommit();
-	void onSetKeyBind(EMouseClickType click, KEY key, MASK mask);
+	void onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore_mask);
 	void onRestoreDefaults();
 	void onDefaultKeyBind();
 
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index 0f0129bf68..be0b8fd4ca 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -58,7 +58,6 @@ static const std::string typetostring[LLKeyConflictHandler::CONTROL_NUM_INDICES]
     "control_wear",
     "control_movements",
     "control_moveto",
-    "control_sit",
     "control_teleportto",
     "push_forward",
     "push_backward",
@@ -69,8 +68,9 @@ static const std::string typetostring[LLKeyConflictHandler::CONTROL_NUM_INDICES]
     "jump",
     "push_down",
     //"control_run",
-    "control_toggle_run",
+    "toggle_run",
     "toggle_fly",
+    "toggle_sit",
     "stop_moving",
     "control_camera",
     "look_up",
@@ -103,8 +103,8 @@ static const std::string typetostring[LLKeyConflictHandler::CONTROL_NUM_INDICES]
     "edit_avatar_move_forward",
     "edit_avatar_move_backward",
     "control_mediacontent",
-    "control_parcel",
-    "control_media",
+    "toggle_pause_media",
+    "toggle_enable_media",
     "control_voice",
     "control_toggle_voice",
     "start_chat",
@@ -161,6 +161,10 @@ static const control_enum_t command_to_key =
     { "stop_moving", LLKeyConflictHandler::CONTROL_STOP },
     { "start_chat", LLKeyConflictHandler::CONTROL_START_CHAT },
     { "start_gesture", LLKeyConflictHandler::CONTROL_START_GESTURE },
+    { "toggle_run", LLKeyConflictHandler::CONTROL_TOGGLE_RUN },
+    { "toggle_sit", LLKeyConflictHandler::CONTROL_SIT },
+    { "toggle_parcel_media", LLKeyConflictHandler::CONTROL_PAUSE_MEDIA },
+    { "toggle_enable_media", LLKeyConflictHandler::CONTROL_ENABLE_MEDIA }, 
 };
 
 
@@ -191,6 +195,60 @@ std::string string_from_mask(MASK mask)
     return res;
 }
 
+std::string string_from_mouse(EMouseClickType click)
+{
+    std::string res;
+    switch (click)
+    {
+    case CLICK_LEFT:
+        res = "LMB";
+        break;
+    case CLICK_MIDDLE:
+        res = "MMB";
+        break;
+    case CLICK_RIGHT:
+        res = "RMB";
+        break;
+    case CLICK_BUTTON4:
+        res = "MB4";
+        break;
+    case CLICK_BUTTON5:
+        res = "MB5";
+        break;
+    case CLICK_DOUBLELEFT:
+        res = "Double LMB";
+        break;
+    default:
+        break;
+    }
+    return res;
+}
+
+EMouseClickType mouse_from_string(const std::string& input)
+{
+    if (input == "LMB")
+    {
+        return CLICK_LEFT;
+    }
+    if (input == "MMB")
+    {
+        return CLICK_MIDDLE;
+    }
+    if (input == "RMB")
+    {
+        return CLICK_RIGHT;
+    }
+    if (input == "MB4")
+    {
+        return CLICK_BUTTON4;
+    }
+    if (input == "MB5")
+    {
+        return CLICK_BUTTON5;
+    }
+    return CLICK_NONE;
+}
+
 // LLKeyConflictHandler
 
 LLKeyConflictHandler::LLKeyConflictHandler()
@@ -245,14 +303,14 @@ bool LLKeyConflictHandler::canAssignControl(EControlTypes control_type)
     return false;
 }
 
-void LLKeyConflictHandler::registerControl(EControlTypes control_type, U32 index, EMouseClickType mouse, KEY key, MASK mask)
+void LLKeyConflictHandler::registerControl(EControlTypes control_type, U32 index, EMouseClickType mouse, KEY key, MASK mask, bool ignore_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);
+    type_data.mKeyBind.replaceKeyData(mouse, key, mask, ignore_mask, index);
 
     mHasUnsavedChanges = true;
 }
@@ -277,45 +335,11 @@ std::string LLKeyConflictHandler::getStringFromKeyData(const LLKeyData& keydata)
     }
     else if (keydata.mMask != MASK_NONE)
     {
-        LL_ERRS() << "Masks binding without keys is not supported yet" << LL_ENDL;
+        result = LLKeyboard::stringFromAccelerator(keydata.mMask);
     }
 
-    #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
+    result += string_from_mouse(keydata.mMouse);
 
-    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;
 }
 
@@ -339,6 +363,8 @@ void  LLKeyConflictHandler::loadFromSettings(const LLViewerKeyboard::KeyMode& ke
     {
         KEY key;
         MASK mask;
+        EMouseClickType mouse = it->mouse.isProvided() ? mouse_from_string(it->mouse) : CLICK_NONE;
+        bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;
         if (it->key.getValue().empty())
         {
             key = KEY_NONE;
@@ -358,7 +384,7 @@ void  LLKeyConflictHandler::loadFromSettings(const LLViewerKeyboard::KeyMode& ke
             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);
+            type_data.mKeyBind.addKeyData(mouse, key, mask, ignore);
         }
     }
 }
@@ -418,6 +444,10 @@ void  LLKeyConflictHandler::loadFromSettings(EModes load_mode)
 {
     mControlsMap.clear();
     mDefaultsMap.clear();
+
+    // E.X. In case we need placeholder keys for conflict resolution.
+    generatePlaceholders(load_mode);
+
     if (load_mode == MODE_GENERAL)
     {
         for (U32 i = 0; i < CONTROL_NUM_INDICES; i++)
@@ -463,12 +493,11 @@ void  LLKeyConflictHandler::loadFromSettings(EModes load_mode)
         }
         else
         {
-            mControlsMap = mDefaultsMap;
+            // mind placeholders
+            mControlsMap.insert(mDefaultsMap.begin(), mDefaultsMap.end());
         }
     }
     mLoadedMode = load_mode;
-
-    generatePlaceholders();
 }
 
 void  LLKeyConflictHandler::saveToSettings()
@@ -555,6 +584,8 @@ void  LLKeyConflictHandler::saveToSettings()
                         binding.key = LLKeyboard::stringFromKey(data.mKey);
                     }
                     binding.mask = string_from_mask(data.mMask);
+                    binding.mouse.set(string_from_mouse(data.mMouse), true); //set() because 'optional', for compatibility purposes
+                    binding.ignore.set(data.mIgnoreMasks, true);
                     binding.command = getControlName(iter->first);
                     mode.bindings.add(binding);
                 }
@@ -711,8 +742,8 @@ void LLKeyConflictHandler::resetToDefaults(EModes mode)
     else
     {
         mControlsMap.clear();
-        mControlsMap = mDefaultsMap;
-        generatePlaceholders();
+        generatePlaceholders(mode);
+        mControlsMap.insert(mDefaultsMap.begin(), mDefaultsMap.end());
     }
 
     mHasUnsavedChanges = true;
@@ -774,7 +805,7 @@ void LLKeyConflictHandler::resetKeyboardBindings()
     gViewerKeyboard.loadBindingsXML(filename);
 }
 
-void LLKeyConflictHandler::generatePlaceholders()
+void LLKeyConflictHandler::generatePlaceholders(EModes load_mode)
 {
 
 }
@@ -784,6 +815,6 @@ void LLKeyConflictHandler::registerTemporaryControl(EControlTypes control_type,
     LLKeyConflict *type_data = &mControlsMap[control_type];
     type_data->mAssignable = false;
     type_data->mConflictMask = conflict_mask;
-    type_data->mKeyBind.addKeyData(mouse, key, mask);
+    type_data->mKeyBind.addKeyData(mouse, key, mask, false);
 }
 
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index 79bd9b8438..7890be1e28 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -95,7 +95,6 @@ public:
         CONTROL_WEAR,
         CONTROL_MOVEMENTS, // Group control, for visual representation
         CONTROL_MOVETO,
-        CONTROL_SIT,
         CONTROL_TELEPORTTO,
         CONTROL_FORWARD,
         CONTROL_BACKWARD,
@@ -108,6 +107,7 @@ public:
         //CONTROL_RUN,
         CONTROL_TOGGLE_RUN,
         CONTROL_TOGGLE_FLY,
+        CONTROL_SIT,
         CONTROL_STOP,
         CONTROL_CAMERA, // Group control, for visual representation
         CONTROL_LOOK_UP,
@@ -140,8 +140,8 @@ public:
         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_PAUSE_MEDIA, // Play pause
+        CONTROL_ENABLE_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
@@ -165,7 +165,7 @@ public:
     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?
+    void registerControl(EControlTypes control_type, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask, bool ignore_mask); //todo: return conflicts?
 
     LLKeyData getControl(EControlTypes control_type, U32 data_index);
 
@@ -202,7 +202,7 @@ private:
     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
+    void generatePlaceholders(EModes load_mode); //E.x. non-assignable values
 
     control_map_t mControlsMap;
     control_map_t mDefaultsMap;
diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp
index 878810e0dd..f1a2b037e2 100644
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -603,12 +603,50 @@ void start_gesture( EKeystate s )
 	}
 }
 
-void toggle_parcel_media(EKeystate s)
+void toggle_run(EKeystate s)
 {
+    if (KEYSTATE_DOWN != s) return;
+    bool run = gAgent.getAlwaysRun();
+    if (run)
+    {
+        gAgent.clearAlwaysRun();
+        gAgent.clearRunning();
+    }
+    else
+    {
+        gAgent.setAlwaysRun();
+        gAgent.setRunning();
+    }
+    gAgent.sendWalkRun(!run);
+}
+
+void toggle_sit(EKeystate s)
+{
+    if (KEYSTATE_DOWN != s) return;
+    if (gAgent.isSitting())
+    {
+        gAgent.standUp();
+    }
+    else
+    {
+        gAgent.sitDown();
+    }
+}
+
+void toggle_pause_media(EKeystate s) // analogue of play/pause button in top bar
+{
+    if (KEYSTATE_DOWN != s) return;
     bool pause = LLViewerMedia::isAnyMediaPlaying();
     LLViewerMedia::setAllMediaPaused(pause);
 }
 
+void toggle_enable_media(EKeystate s)
+{
+    if (KEYSTATE_DOWN != s) return;
+    bool pause = LLViewerMedia::isAnyMediaPlaying() || LLViewerMedia::isAnyMediaShowing();
+    LLViewerMedia::setAllMediaEnabled(!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);
@@ -650,20 +688,24 @@ 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);
+REGISTER_KEYBOARD_ACTION("toggle_run", toggle_run);
+REGISTER_KEYBOARD_ACTION("toggle_sit", toggle_sit);
+REGISTER_KEYBOARD_ACTION("toggle_pause_media", toggle_pause_media);
+REGISTER_KEYBOARD_ACTION("toggle_enable_media", toggle_enable_media);
 #undef REGISTER_KEYBOARD_ACTION
 
 LLViewerKeyboard::LLViewerKeyboard()
 {
-	for (S32 i = 0; i < MODE_COUNT; i++)
-	{
-		mBindingCount[i] = 0;
-	}
+    resetBindings();
 
 	for (S32 i = 0; i < KEY_COUNT; i++)
 	{
 		mKeyHandledByUI[i] = FALSE;
-	}
+    }
+    for (S32 i = 0; i < CLICK_COUNT; i++)
+    {
+        mMouseLevel[i] = MOUSE_STATE_SILENT;
+    }
 	// we want the UI to never see these keys so that they can always control the avatar/camera
 	for(KEY k = KEY_PAD_UP; k <= KEY_PAD_DIVIDE; k++) 
 	{
@@ -671,7 +713,7 @@ LLViewerKeyboard::LLViewerKeyboard()
 	}
 }
 
-BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode)
+BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode) const
 {
 	if (string == "FIRST_PERSON")
 	{
@@ -705,6 +747,40 @@ BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode)
 	}
 }
 
+BOOL LLViewerKeyboard::mouseFromString(const std::string& string, EMouseClickType *mode) const
+{
+    if (string == "LMB")
+    {
+        *mode = CLICK_LEFT;
+        return TRUE;
+    }
+    else if (string == "DLMB")
+    {
+        *mode = CLICK_DOUBLELEFT;
+        return TRUE;
+    }
+    else if (string == "MMB")
+    {
+        *mode = CLICK_MIDDLE;
+        return TRUE;
+    }
+    else if (string == "MB4")
+    {
+        *mode = CLICK_BUTTON4;
+        return TRUE;
+    }
+    else if (string == "MB5")
+    {
+        *mode = CLICK_BUTTON5;
+        return TRUE;
+    }
+    else
+    {
+        *mode = CLICK_NONE;
+        return FALSE;
+    }
+}
+
 BOOL LLViewerKeyboard::handleKey(KEY translated_key,  MASK translated_mask, BOOL repeated)
 {
 	// check for re-map
@@ -748,7 +824,7 @@ BOOL LLViewerKeyboard::handleKeyUp(KEY translated_key, MASK translated_mask)
 	return gViewerWindow->handleKeyUp(translated_key, translated_mask);
 }
 
-BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name)
+BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const bool ignore, const std::string& function_name)
 {
 	S32 index;
 	typedef boost::function<void(EKeystate)> function_t;
@@ -789,11 +865,22 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c
 	}
 
 	// check for duplicate first and overwrite
-	for (index = 0; index < mBindingCount[mode]; index++)
-	{
-		if (key == mBindings[mode][index].mKey && mask == mBindings[mode][index].mMask)
-			break;
-	}
+    if (ignore)
+    {
+        for (index = 0; index < mKeyIgnoreMaskCount[mode]; index++)
+        {
+            if (key == mKeyIgnoreMask[mode][index].mKey)
+                break;
+        }
+    }
+    else
+    {
+        for (index = 0; index < mKeyBindingCount[mode]; index++)
+        {
+            if (key == mKeyBindings[mode][index].mKey && mask == mKeyBindings[mode][index].mMask)
+                break;
+        }
+    }
 
 	if (index >= MAX_KEY_BINDINGS)
 	{
@@ -807,20 +894,102 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c
 		return FALSE;
 	}
 
-	mBindings[mode][index].mKey = key;
-	mBindings[mode][index].mMask = mask;
-	mBindings[mode][index].mFunction = function;
+    if (ignore)
+    {
+        mKeyIgnoreMask[mode][index].mKey = key;
+        mKeyIgnoreMask[mode][index].mFunction = function;
+
+        if (index == mKeyIgnoreMaskCount[mode])
+            mKeyIgnoreMaskCount[mode]++;
+    }
+    else
+    {
+        mKeyBindings[mode][index].mKey = key;
+        mKeyBindings[mode][index].mMask = mask;
+        mKeyBindings[mode][index].mFunction = function;
 
-	if (index == mBindingCount[mode])
-        mBindingCount[mode]++;
+        if (index == mKeyBindingCount[mode])
+            mKeyBindingCount[mode]++;
+    }
 
 	return TRUE;
 }
 
+BOOL LLViewerKeyboard::bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const bool ignore, const std::string& function_name)
+{
+    S32 index;
+    typedef boost::function<void(EKeystate)> function_t;
+    function_t function = NULL;
+
+    function_t* result = LLKeyboardActionRegistry::getValue(function_name);
+    if (result)
+    {
+        function = *result;
+    }
+
+    if (!function)
+    {
+        LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
+        return FALSE;
+    }
+
+    // check for duplicate first and overwrite
+    if (ignore)
+    {
+        for (index = 0; index < mMouseIgnoreMaskCount[mode]; index++)
+        {
+            if (mouse == mMouseIgnoreMask[mode][index].mMouse)
+                break;
+        }
+    }
+    else
+    {
+        for (index = 0; index < mMouseBindingCount[mode]; index++)
+        {
+            if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask)
+                break;
+        }
+    }
+
+    if (index >= MAX_KEY_BINDINGS)
+    {
+        LL_ERRS() << "LLKeyboard::bindKey() - too many keys for mode " << mode << LL_ENDL;
+        return FALSE;
+    }
+
+    if (mode >= MODE_COUNT)
+    {
+        LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
+        return FALSE;
+    }
+
+    if (ignore)
+    {
+        mMouseIgnoreMask[mode][index].mMouse = mouse;
+        mMouseIgnoreMask[mode][index].mFunction = function;
+
+        if (index == mMouseIgnoreMaskCount[mode])
+            mMouseIgnoreMaskCount[mode]++;
+    }
+    else
+    {
+        mMouseBindings[mode][index].mMouse = mouse;
+        mMouseBindings[mode][index].mMask = mask;
+        mMouseBindings[mode][index].mFunction = function;
+
+        if (index == mMouseBindingCount[mode])
+            mMouseBindingCount[mode]++;
+    }
+
+    return TRUE;
+}
+
 LLViewerKeyboard::KeyBinding::KeyBinding()
 :	key("key"),
+	mouse("mouse"),
 	mask("mask"),
-	command("command")
+	command("command"),
+	ignore("ignore", false)
 {}
 
 LLViewerKeyboard::KeyMode::KeyMode()
@@ -835,12 +1004,20 @@ LLViewerKeyboard::Keys::Keys()
 	edit_avatar("edit_avatar")
 {}
 
+void LLViewerKeyboard::resetBindings()
+{
+    for (S32 i = 0; i < MODE_COUNT; i++)
+    {
+        mKeyBindingCount[i] = 0;
+        mKeyIgnoreMaskCount[i] = 0;
+        mMouseBindingCount[i] = 0;
+        mMouseIgnoreMaskCount[i] = 0;
+    }
+}
+
 S32 LLViewerKeyboard::loadBindingsXML(const std::string& filename)
 {
-	for (S32 i = 0; i < MODE_COUNT; i++)
-	{
-		mBindingCount[i] = 0;
-	}
+    resetBindings();
 
 	S32 binding_count = 0;
 	Keys keys;
@@ -870,9 +1047,20 @@ S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode,
         {
             KEY key;
             MASK mask;
+            bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;
             LLKeyboard::keyFromString(it->key, &key);
             LLKeyboard::maskFromString(it->mask, &mask);
-            bindKey(mode, key, mask, it->command);
+            bindKey(mode, key, mask, ignore, it->command);
+            binding_count++;
+        }
+        else if (it->mouse.isProvided() && !it->mouse.getValue().empty())
+        {
+            EMouseClickType mouse;
+            MASK mask;
+            bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;
+            mouseFromString(it->mouse.getValue(), &mouse);
+            LLKeyboard::maskFromString(it->mask, &mask);
+            bindMouse(mode, mouse, mask, ignore, it->command);
             binding_count++;
         }
 	}
@@ -964,7 +1152,7 @@ S32 LLViewerKeyboard::loadBindings(const std::string& filename)
 		}
 
 		// bind key
-		if (bindKey(mode, key, mask, function_string))
+		if (bindKey(mode, key, mask, false, function_string))
 		{
 			binding_count++;
 		}
@@ -976,7 +1164,7 @@ S32 LLViewerKeyboard::loadBindings(const std::string& filename)
 }
 
 
-EKeyboardMode LLViewerKeyboard::getMode()
+EKeyboardMode LLViewerKeyboard::getMode() const
 {
 	if ( gAgentCamera.cameraMouselook() )
 	{
@@ -996,56 +1184,184 @@ EKeyboardMode LLViewerKeyboard::getMode()
 	}
 }
 
-
-// Called from scanKeyboard.
-void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
+bool LLViewerKeyboard::scanKey(const LLKeyboardBinding* binding,
+                               S32 binding_count,
+                               KEY key,
+                               MASK mask,
+                               BOOL key_down,
+                               BOOL key_up,
+                               BOOL key_level,
+                               bool repeat) const
 {
-	if (LLApp::isExiting())
-	{
-		return;
-	}
-
-	S32 mode = getMode();
-	// Consider keyboard scanning as NOT mouse event. JC
-	MASK mask = gKeyboard->currentMask(FALSE);
-
-	LLKeyBinding* binding = mBindings[mode];
-	S32 binding_count = mBindingCount[mode];
-
-
-	if (mKeyHandledByUI[key])
-	{
-		return;
-	}
-
-	// don't process key down on repeated keys
-	BOOL repeat = gKeyboard->getKeyRepeated(key);
-
 	for (S32 i = 0; i < binding_count; i++)
 	{
-		//for (S32 key = 0; key < KEY_COUNT; key++)
 		if (binding[i].mKey == key)
 		{
-			//if (binding[i].mKey == key && binding[i].mMask == mask)
 			if (binding[i].mMask == mask)
 			{
 				if (key_down && !repeat)
 				{
 					// ...key went down this frame, call function
 					binding[i].mFunction( KEYSTATE_DOWN );
+					return true;
 				}
 				else if (key_up)
 				{
 					// ...key went down this frame, call function
 					binding[i].mFunction( KEYSTATE_UP );
+					return true;
 				}
 				else if (key_level)
 				{
 					// ...key held down from previous frame
 					// Not windows, just call the function.
 					binding[i].mFunction( KEYSTATE_LEVEL );
+					return true;
 				}//if
+				// Key+Mask combinations are supposed to be unique, so we won't find anything else
+				return false;
 			}//if
-		}//for
+		}//if
 	}//for
+	return false;
+}
+
+// Called from scanKeyboard.
+void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) const
+{
+	if (LLApp::isExiting())
+	{
+		return;
+	}
+
+	S32 mode = getMode();
+	// Consider keyboard scanning as NOT mouse event. JC
+	MASK mask = gKeyboard->currentMask(FALSE);
+
+	if (mKeyHandledByUI[key])
+	{
+		return;
+	}
+
+	// don't process key down on repeated keys
+	BOOL repeat = gKeyboard->getKeyRepeated(key);
+
+    if (scanKey(mKeyBindings[mode], mKeyBindingCount[mode], key, mask, key_down, key_up, key_level, repeat))
+    {
+        // Nothing found, try ignore list
+        scanKey(mKeyIgnoreMask[mode], mKeyIgnoreMaskCount[mode], key, MASK_NONE, key_down, key_up, key_level, repeat);
+    }
+}
+
+BOOL LLViewerKeyboard::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down)
+{
+    BOOL handled = gViewerWindow->handleAnyMouseClick(window_impl, pos, mask, clicktype, down);
+
+    if (clicktype != CLICK_NONE)
+    {
+        // special case
+        // if UI doesn't handle double click, LMB click is issued, so supres LMB 'down' when doubleclick is set
+        // handle !down as if we are handling doubleclick
+        bool override_lmb = (clicktype == CLICK_LEFT
+            && (mMouseLevel[CLICK_DOUBLELEFT] == MOUSE_STATE_DOWN || mMouseLevel[CLICK_DOUBLELEFT] == MOUSE_STATE_LEVEL));
+
+        if (override_lmb && !down)
+        {
+            // process doubleclick instead
+            clicktype = CLICK_DOUBLELEFT;
+        }
+
+        if (override_lmb && down)
+        {
+            // else-supress
+        }
+        // if UI handled 'down', it should handle 'up' as well
+        // if we handle 'down' not by UI, then we should handle 'up'/'level' regardless of UI
+        else if (handled && mMouseLevel[clicktype] != MOUSE_STATE_SILENT)
+        {
+            // UI handled new 'down' so iterupt whatever state we were in.
+            mMouseLevel[clicktype] = MOUSE_STATE_UP;
+        }
+        else if (down)
+        {
+            if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN)
+            {
+                // this is repeated hit (mouse does not repeat event until release)
+                // for now treat rapid clicking like mouse being held
+                mMouseLevel[clicktype] = MOUSE_STATE_LEVEL;
+            }
+            else
+            {
+                mMouseLevel[clicktype] = MOUSE_STATE_DOWN;
+            }
+        }
+        else
+        {
+            // Released mouse key
+            mMouseLevel[clicktype] = MOUSE_STATE_UP;
+        }
+    }
+
+    return handled;
+}
+
+bool LLViewerKeyboard::scanMouse(const LLMouseBinding *binding, S32 binding_count, EMouseClickType mouse, MASK mask, EMouseState state) const
+{
+    for (S32 i = 0; i < binding_count; i++)
+    {
+        if (binding[i].mMouse == mouse && binding[i].mMask == mask)
+        {
+            switch (state)
+            {
+            case MOUSE_STATE_DOWN:
+                binding[i].mFunction(KEYSTATE_DOWN);
+                break;
+            case MOUSE_STATE_LEVEL:
+                binding[i].mFunction(KEYSTATE_LEVEL);
+                break;
+            case MOUSE_STATE_UP:
+                binding[i].mFunction(KEYSTATE_UP);
+                break;
+            default:
+                break;
+            }
+            // Key+Mask combinations are supposed to be unique, no need to continue
+            return true;
+        }
+    }
+    return false;
+}
+
+// todo: this recods key, scanMouse() triggers functions with EKeystate
+bool LLViewerKeyboard::scanMouse(EMouseClickType click, EMouseState state) const
+{
+    bool res = false;
+    S32 mode = getMode();
+    MASK mask = gKeyboard->currentMask(TRUE);
+    res = scanMouse(mMouseBindings[mode], mMouseBindingCount[mode], click, mask, state);
+    if (!res)
+    {
+        res = scanMouse(mMouseIgnoreMask[mode], mMouseIgnoreMaskCount[mode], click, MASK_NONE, state);
+    }
+    return res;
+}
+
+void LLViewerKeyboard::scanMouse()
+{
+    for (S32 i = 0; i < CLICK_COUNT; i++)
+    {
+        if (mMouseLevel[i] != MOUSE_STATE_SILENT)
+        {
+            scanMouse((EMouseClickType)i, mMouseLevel[i]);
+            if (mMouseLevel[i] == MOUSE_STATE_DOWN)
+            {
+                // mouse doesn't support 'continued' state like keyboard does, so after handling, switch to LEVEL
+                mMouseLevel[i] = MOUSE_STATE_LEVEL;
+            }
+            else if (mMouseLevel[i] == MOUSE_STATE_UP)
+            {
+                mMouseLevel[i] = MOUSE_STATE_SILENT;
+            }
+        }
+    }
 }
diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h
index 2bfe285be4..3ba033509c 100644
--- a/indra/newview/llviewerkeyboard.h
+++ b/indra/newview/llviewerkeyboard.h
@@ -43,6 +43,27 @@ public:
 	LLKeyFunc	mFunction;
 };
 
+class LLKeyboardBinding
+{
+public:
+    KEY				mKey;
+    MASK			mMask;
+    bool			mIgnoreMask; // whether CTRL/ALT/SHIFT should be checked
+
+    LLKeyFunc		mFunction;
+};
+
+class LLMouseBinding
+{
+public:
+    EMouseClickType	mMouse;
+    MASK			mMask;
+    bool			mIgnoreMask; // whether CTRL/ALT/SHIFT should be checked
+
+    LLKeyFunc		mFunction;
+};
+
+
 typedef enum e_keyboard_mode
 {
 	MODE_FIRST_PERSON,
@@ -53,6 +74,7 @@ typedef enum e_keyboard_mode
 	MODE_COUNT
 } EKeyboardMode;
 
+class LLWindow;
 
 void bind_keyboard_functions();
 
@@ -64,6 +86,8 @@ public:
 		Mandatory<std::string>	key,
 								mask,
 								command;
+		Optional<std::string>	mouse; // Note, not mandatory for the sake of backward campatibility
+		Optional<bool>			ignore;
 
 		KeyBinding();
 	};
@@ -93,24 +117,68 @@ public:
 
 	S32				loadBindings(const std::string& filename);										// returns number bound, 0 on error
 	S32				loadBindingsXML(const std::string& filename);										// returns number bound, 0 on error
-	EKeyboardMode	getMode();
+	EKeyboardMode	getMode() const;
+
+	BOOL			modeFromString(const std::string& string, S32 *mode) const;			// False on failure
+	BOOL			mouseFromString(const std::string& string, EMouseClickType *mode) const;// False on failure
 
-	BOOL			modeFromString(const std::string& string, S32 *mode);			// False on failure
+    void			scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) const;
 
-	void			scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level);
+    // handleMouse() records state, scanMouse() goes through states, scanMouse(click) processes individual saved states after UI is done with them
+    BOOL			handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down);
+	void LLViewerKeyboard::scanMouse();
 
 private:
-	S32				loadBindingMode(const LLViewerKeyboard::KeyMode& keymode, S32 mode);
-	BOOL			bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name);
+    bool            scanKey(const LLKeyboardBinding* binding,
+                            S32 binding_count,
+                            KEY key,
+                            MASK mask,
+                            BOOL key_down,
+                            BOOL key_up,
+                            BOOL key_level,
+                            bool repeat) const;
+
+    enum EMouseState
+    {
+        MOUSE_STATE_DOWN, // key down this frame
+        MOUSE_STATE_LEVEL, // clicked again fast, or never released
+        MOUSE_STATE_UP, // went up this frame
+        MOUSE_STATE_SILENT // notified about 'up', do not notify again
+    };
+    bool			scanMouse(EMouseClickType click, EMouseState state) const;
+    bool            scanMouse(const LLMouseBinding *binding,
+                          S32 binding_count,
+                          EMouseClickType mouse,
+                          MASK mask,
+                          EMouseState state) const;
+
+    S32				loadBindingMode(const LLViewerKeyboard::KeyMode& keymode, S32 mode);
+    BOOL			bindKey(const S32 mode, const KEY key, const MASK mask, const bool ignore, const std::string& function_name);
+    BOOL			bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const bool ignore, const std::string& function_name);
+    void			resetBindings();
 
 	// Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here
-	S32				mBindingCount[MODE_COUNT];
-	LLKeyBinding	mBindings[MODE_COUNT][MAX_KEY_BINDINGS];
+    // We process specific keys first, then keys that should ignore mask.
+    // This way with W+ignore defined to 'forward' and with ctrl+W tied to camera,
+    // pressing undefined Shift+W will do 'forward', yet ctrl+W will do 'camera forward'
+    // With A defined to 'turn', shift+A defined to strafe, pressing Shift+W+A will do strafe+forward
+    S32				mKeyBindingCount[MODE_COUNT];
+    S32				mKeyIgnoreMaskCount[MODE_COUNT];
+    S32				mMouseBindingCount[MODE_COUNT];
+    S32				mMouseIgnoreMaskCount[MODE_COUNT];
+    LLKeyboardBinding	mKeyBindings[MODE_COUNT][MAX_KEY_BINDINGS];
+    LLKeyboardBinding	mKeyIgnoreMask[MODE_COUNT][MAX_KEY_BINDINGS];
+    LLMouseBinding		mMouseBindings[MODE_COUNT][MAX_KEY_BINDINGS];
+    LLMouseBinding		mMouseIgnoreMask[MODE_COUNT][MAX_KEY_BINDINGS];
 
 	typedef std::map<U32, U32> key_remap_t;
 	key_remap_t		mRemapKeys[MODE_COUNT];
 	std::set<KEY>	mKeysSkippedByUI;
 	BOOL			mKeyHandledByUI[KEY_COUNT];		// key processed successfully by UI
+
+    // This is indentical to what llkeyboard does (mKeyRepeated, mKeyLevel, mKeyDown e t c),
+    // just instead of remembering individually as bools,  we record state as enum
+    EMouseState		mMouseLevel[CLICK_COUNT];	// records of key state
 };
 
 extern LLViewerKeyboard gViewerKeyboard;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 2c58295814..bd5370f07f 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -898,6 +898,17 @@ LLViewerWindow::Params::Params()
 {}
 
 
+void LLViewerWindow::handlePieMenu(S32 x, S32 y, MASK mask)
+{
+    if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance() && gAgent.isInitialized())
+    {
+        // If the current tool didn't process the click, we should show
+        // the pie menu.  This can be done by passing the event to the pie
+        // menu tool.
+        LLToolPie::getInstance()->handleRightMouseDown(x, y, mask);
+    }
+}
+
 BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down)
 {
 	const char* buttonname = "";
@@ -996,6 +1007,11 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK m
 				LLViewerEventRecorder::instance().logMouseEvent(std::string(buttonstatestr),std::string(buttonname)); 
 
 			}
+			else if (down && clicktype == CLICK_RIGHT)
+			{
+				handlePieMenu(x, y, mask);
+				r = TRUE;
+			}
 			return r;
 		}
 
@@ -1042,7 +1058,12 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK m
 		return TRUE;
 	}
 
-	
+	if (down && clicktype == CLICK_RIGHT)
+	{
+		handlePieMenu(x, y, mask);
+		return TRUE;
+	}
+
 	// If we got this far on a down-click, it wasn't handled.
 	// Up-clicks, though, are always handled as far as the OS is concerned.
 	BOOL default_rtn = !down;
@@ -1061,7 +1082,8 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask
         mMouseDownTimer.reset();
     }    
     BOOL down = TRUE;
-	return handleAnyMouseClick(window, pos, mask, CLICK_LEFT, down);
+    //handleMouse() loops back to LLViewerWindow::handleAnyMouseClick
+    return gViewerKeyboard.handleMouse(window, pos, mask, CLICK_LEFT, down);
 }
 
 BOOL LLViewerWindow::handleDoubleClick(LLWindow *window,  LLCoordGL pos, MASK mask)
@@ -1069,7 +1091,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, CLICK_DOUBLELEFT, down))
+	if (gViewerKeyboard.handleMouse(window, pos, mask, CLICK_DOUBLELEFT, down))
 	{
 		return TRUE;
 	}
@@ -1083,46 +1105,24 @@ BOOL LLViewerWindow::handleMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)
         mMouseDownTimer.stop();
     }
     BOOL down = FALSE;
-	return handleAnyMouseClick(window, pos, mask, CLICK_LEFT, down);
+    return gViewerKeyboard.handleMouse(window, pos, mask, CLICK_LEFT, down);
 }
-
-
 BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask)
 {
-	S32 x = pos.mX;
-	S32 y = pos.mY;
-	x = ll_round((F32)x / mDisplayScale.mV[VX]);
-	y = ll_round((F32)y / mDisplayScale.mV[VY]);
-
 	BOOL down = TRUE;
-	BOOL handle = handleAnyMouseClick(window, pos, mask, CLICK_RIGHT, down);
-	if (handle)
-		return handle;
-
-	// *HACK: this should be rolled into the composite tool logic, not
-	// hardcoded at the top level.
-	if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance() && gAgent.isInitialized())
-	{
-		// If the current tool didn't process the click, we should show
-		// the pie menu.  This can be done by passing the event to the pie
-		// menu tool.
-		LLToolPie::getInstance()->handleRightMouseDown(x, y, mask);
-		// show_context_menu( x, y, mask );
-	}
-
-	return TRUE;
+	return gViewerKeyboard.handleMouse(window, pos, mask, CLICK_RIGHT, down);
 }
 
 BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)
 {
 	BOOL down = FALSE;
- 	return handleAnyMouseClick(window, pos, mask, CLICK_RIGHT, down);
+ 	return gViewerKeyboard.handleMouse(window, pos, mask, CLICK_RIGHT, down);
 }
 
 BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask)
 {
 	BOOL down = TRUE;
- 	handleAnyMouseClick(window, pos, mask, CLICK_MIDDLE, down);
+ 	gViewerKeyboard.handleMouse(window, pos, mask, CLICK_MIDDLE, down);
   
   	// Always handled as far as the OS is concerned.
 	return TRUE;
@@ -1277,7 +1277,7 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi
 BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)
 {
 	BOOL down = FALSE;
- 	handleAnyMouseClick(window, pos, mask, CLICK_MIDDLE, down);
+ 	gViewerKeyboard.handleMouse(window, pos, mask, CLICK_MIDDLE, down);
   
   	// Always handled as far as the OS is concerned.
 	return TRUE;
@@ -1288,10 +1288,10 @@ BOOL LLViewerWindow::handleOtherMouse(LLWindow *window, LLCoordGL pos, MASK mask
     switch (button)
     {
     case 4:
-        handleAnyMouseClick(window, pos, mask, CLICK_BUTTON4, down);
+        gViewerKeyboard.handleMouse(window, pos, mask, CLICK_BUTTON4, down);
         break;
     case 5:
-        handleAnyMouseClick(window, pos, mask, CLICK_BUTTON5, down);
+        gViewerKeyboard.handleMouse(window, pos, mask, CLICK_BUTTON5, down);
         break;
     default:
         break;
@@ -1458,7 +1458,8 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key,  MASK mask, BOOL repeated)
     		return FALSE;
 	}
 
-	return gViewerKeyboard.handleKey(key, mask, repeated);
+    // remaps, handles ignored cases and returns back to viewer window.
+    return gViewerKeyboard.handleKey(key, mask, repeated);
 }
 
 BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key,  MASK mask)
@@ -2936,6 +2937,7 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
 	{
 		if (mask != MASK_ALT)
 		{
+			// remaps, handles ignored cases and returns back to viewer window.
 			return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
 		}
 	}
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 5f03685cee..a6365ab328 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -175,8 +175,9 @@ public:
 	void			initWorldUI();
 	void			setUIVisibility(bool);
 	bool			getUIVisibility();
+	void			handlePieMenu(S32 x, S32 y, MASK mask);
 
-	BOOL handleAnyMouseClick(LLWindow *window,  LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down);
+	BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down);
 
 	//
 	// LLWindowCallback interface implementation
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 c00b805954..32f091938e 100644
--- a/indra/newview/skins/default/xui/en/floater_select_key.xml
+++ b/indra/newview/skins/default/xui/en/floater_select_key.xml
@@ -4,7 +4,7 @@
  border="false"
  can_close="false"
  can_minimize="false"
- height="90"
+ height="116"
  layout="topleft"
  name="modal container"
  width="272">
@@ -31,13 +31,25 @@
 Press a key to set your trigger.
 Allowed input: [INPUT].
     </text>
+    <check_box
+     follows="top|left"
+     height="20"
+     initial_value="false"
+     label="Ignore accelerator keys"
+     layout="topleft"
+     left="8"
+     name="ignore_masks"
+     tool_tip="Ignore Shift, Alt and Ctrl keys. Example: This allows to hold W (forward, ignores shift) and Shift+A (slide left) simultaneously and agent will both move forward and slide left."
+     top_pad="8"
+     width="160" />
+  
     <button
      height="23"
      label="Set Empty"
      layout="topleft"
      left="8"
      name="SetEmpty"
-     top_pad="8"
+     top_pad="6"
      width="80" />
     <button
      height="23"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
index 1bfee20c81..0c652845f0 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
@@ -74,7 +74,7 @@
     Move To
   </panel.string>
   <panel.string
-   name="control_sit">
+   name="toggle_sit">
     Sit/Stand
   </panel.string>
   <panel.string
@@ -119,7 +119,7 @@
     Run
   </panel.string>
   <panel.string
-   name="control_toggle_run">
+   name="toggle_run">
     Toggle Run
   </panel.string>
   <panel.string
@@ -207,11 +207,11 @@
     Sound and Media
   </panel.string>
   <panel.string
-   name="control_parcel">
-    Play/Pause Parcel Media
+   name="toggle_pause_media">
+    Play/Pause Media
   </panel.string>
   <panel.string
-   name="control_media">
+   name="toggle_enable_media">
     Play/Stop All Media
   </panel.string>
   <panel.string
-- 
cgit v1.2.3


From 8f35d638fbdbbdcf80ad1e6d826fd6161a0a2387 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Wed, 25 Sep 2019 22:23:09 +0300
Subject: SL-6109 LMB DLMB in progress

---
 indra/newview/llfloaterpreference.cpp |  11 +-
 indra/newview/llkeyconflict.cpp       |  60 +++------
 indra/newview/llkeyconflict.h         |  10 +-
 indra/newview/lltool.cpp              |   2 +-
 indra/newview/lltoolpie.cpp           | 226 +++++++++++++---------------------
 indra/newview/lltoolpie.h             |   2 +-
 indra/newview/llviewerkeyboard.cpp    | 114 ++++++++++++-----
 indra/newview/llviewerkeyboard.h      |   1 +
 indra/newview/llviewermenu.cpp        |   1 -
 9 files changed, 213 insertions(+), 214 deletions(-)

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 9c706a0d3a..6085c92f49 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -167,7 +167,7 @@ static const U32 ALLOW_KEYS = 4; //keyboard
 static const U32 ALLOW_MASK_KEYS = 8;
 static const U32 ALLOW_MASKS = 16;
 static const U32 CAN_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;
+static const U32 DEFAULT_KEY_FILTER = ALLOW_MOUSE | ALLOW_MASK_MOUSE | ALLOW_KEYS | ALLOW_MASK_KEYS | CAN_IGNORE_MASKS;
 
 class LLSetKeyBindDialog : public LLModalDialog
 {
@@ -2970,6 +2970,10 @@ LLPanelPreferenceControls::LLPanelPreferenceControls()
     mEditingMode(0),
     mShowKeyDialog(false)
 {
+    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i)
+    {
+        mConflictHandler[i].setLoadMode((LLKeyConflictHandler::EModes)i);
+    }
 }
 
 LLPanelPreferenceControls::~LLPanelPreferenceControls()
@@ -3294,7 +3298,10 @@ void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MAS
 
 void LLPanelPreferenceControls::onRestoreDefaults()
 {
-    mConflictHandler[mEditingMode].resetToDefaults();
+    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i)
+    {
+        mConflictHandler[mEditingMode].resetToDefaults();
+    }
     populateControlTable();
 }
 
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index be0b8fd4ca..87ea408a6a 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -57,8 +57,8 @@ static const std::string typetostring[LLKeyConflictHandler::CONTROL_NUM_INDICES]
     "control_touch",
     "control_wear",
     "control_movements",
-    "control_moveto",
-    "control_teleportto",
+    "walk_to",
+    "teleport_to",
     "push_forward",
     "push_backward",
     "turn_left",
@@ -164,7 +164,9 @@ static const control_enum_t command_to_key =
     { "toggle_run", LLKeyConflictHandler::CONTROL_TOGGLE_RUN },
     { "toggle_sit", LLKeyConflictHandler::CONTROL_SIT },
     { "toggle_parcel_media", LLKeyConflictHandler::CONTROL_PAUSE_MEDIA },
-    { "toggle_enable_media", LLKeyConflictHandler::CONTROL_ENABLE_MEDIA }, 
+    { "toggle_enable_media", LLKeyConflictHandler::CONTROL_ENABLE_MEDIA },
+    { "walk_to", LLKeyConflictHandler::CONTROL_MOVETO },
+    { "teleport_to", LLKeyConflictHandler::CONTROL_TELEPORTTO },
 };
 
 
@@ -268,7 +270,7 @@ LLKeyConflictHandler::LLKeyConflictHandler()
 
 LLKeyConflictHandler::LLKeyConflictHandler(EModes mode)
     : mHasUnsavedChanges(false),
-    mLoadedMode(mode)
+    mLoadMode(mode)
 {
     loadFromSettings(mode);
 }
@@ -497,7 +499,7 @@ void  LLKeyConflictHandler::loadFromSettings(EModes load_mode)
             mControlsMap.insert(mDefaultsMap.begin(), mDefaultsMap.end());
         }
     }
-    mLoadedMode = load_mode;
+    mLoadMode = load_mode;
 }
 
 void  LLKeyConflictHandler::saveToSettings()
@@ -507,7 +509,7 @@ void  LLKeyConflictHandler::saveToSettings()
         return;
     }
 
-    if (mLoadedMode == MODE_GENERAL)
+    if (mLoadMode == MODE_GENERAL)
     {
         for (U32 i = 0; i < CONTROL_NUM_INDICES; i++)
         {
@@ -591,7 +593,7 @@ void  LLKeyConflictHandler::saveToSettings()
                 }
             }
 
-            switch (mLoadedMode)
+            switch (mLoadMode)
             {
             case MODE_FIRST_PERSON:
                 if (keys.first_person.isProvided())
@@ -657,7 +659,7 @@ void  LLKeyConflictHandler::saveToSettings()
 
 LLKeyData LLKeyConflictHandler::getDefaultControl(EControlTypes control_type, U32 index)
 {
-    if (mLoadedMode == MODE_GENERAL)
+    if (mLoadMode == MODE_GENERAL)
     {
         std::string name = getControlName(control_type);
         LLControlVariablePtr var = gSavedSettings.getControl(name);
@@ -686,7 +688,7 @@ void LLKeyConflictHandler::resetToDefault(EControlTypes control_type, U32 index)
 
 void LLKeyConflictHandler::resetToDefault(EControlTypes control_type)
 {
-    if (mLoadedMode == MODE_GENERAL)
+    if (mLoadMode == MODE_GENERAL)
     {
         std::string name = getControlName(control_type);
         LLControlVariablePtr var = gSavedSettings.getControl(name);
@@ -753,40 +755,18 @@ void LLKeyConflictHandler::resetToDefaults()
 {
     if (!empty())
     {
-        resetToDefaults(mLoadedMode);
+        resetToDefaults(mLoadMode);
     }
-}
-
-void LLKeyConflictHandler::resetAllToDefaults()
-{
-    std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "keys.xml");
-    if (gDirUtilp->fileExists(filename))
+    else
     {
-        LLFile::remove(filename);
-        std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "keys.xml");
-        gViewerKeyboard.loadBindingsXML(filename);
+        // not optimal since:
+        // 1. We are not sure that mLoadMode was set
+        // 2. We are not sure if there are any changes in comparison to default
+        // 3. We are loading 'current' only to replace it
+        // but it is reliable and works Todo: consider optimizing.
+        loadFromSettings(mLoadMode);
+        resetToDefaults(mLoadMode);
     }
-
-    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()
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index 7890be1e28..b0f99e2d0c 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -183,18 +183,20 @@ public:
     // 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);
+    // resets current mode to defaults, 
     void resetToDefaults();
-    void resetAllToDefaults();
 
     bool empty() { return mControlsMap.empty(); }
     void clear();
 
     bool hasUnsavedChanges() { return mHasUnsavedChanges; }
-    EModes getLoadedMode() { return mLoadedMode; }
+    void setLoadMode(EModes mode) { mLoadMode = mode; }
+    EModes getLoadMode() { return mLoadMode; }
     // todo: conflict search
 
 private:
+    void resetToDefaults(EModes mode);
+
     // 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);
 
@@ -207,7 +209,7 @@ private:
     control_map_t mControlsMap;
     control_map_t mDefaultsMap;
     bool mHasUnsavedChanges;
-    EModes mLoadedMode;
+    EModes mLoadMode;
 };
 
 
diff --git a/indra/newview/lltool.cpp b/indra/newview/lltool.cpp
index 0038138078..e2ab450d8c 100644
--- a/indra/newview/lltool.cpp
+++ b/indra/newview/lltool.cpp
@@ -85,7 +85,7 @@ BOOL LLTool::handleMouseDown(S32 x, S32 y, MASK mask)
 	// by default, didn't handle it
 	// LL_INFOS() << "LLTool::handleMouseDown" << LL_ENDL;
 	gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN);
-	return TRUE;
+	return FALSE;
 }
 
 BOOL LLTool::handleMouseUp(S32 x, S32 y, MASK mask)
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 0b569b4fe8..4edfd7fb39 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -83,7 +83,6 @@ LLToolPie::LLToolPie()
 	mMouseOutsideSlop( false ),
 	mMouseSteerX(-1),
 	mMouseSteerY(-1),
-	mBlockClickToWalk(false),
 	mClickAction(0),
 	mClickActionBuyEnabled( gSavedSettings.getBOOL("ClickActionBuyEnabled") ),
 	mClickActionPayEnabled( gSavedSettings.getBOOL("ClickActionPayEnabled") ),
@@ -172,10 +171,8 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)
 	mPick.mKeyMask = mask;
 
 	mMouseButtonDown = true;
-	
-	handleLeftClickPick();
 
-	return TRUE;
+    return handleLeftClickPick();
 }
 
 // Spawn context menus on right mouse down so you can drag over and select
@@ -374,8 +371,6 @@ BOOL LLToolPie::handleLeftClickPick()
 	// put focus back "in world"
 	if (gFocusMgr.getKeyboardFocus())
 	{
-		// don't click to walk on attempt to give focus to world
-		mBlockClickToWalk = true;
 		gFocusMgr.setKeyboardFocus(NULL);
 	}
 
@@ -419,7 +414,7 @@ BOOL LLToolPie::handleLeftClickPick()
 		}
 		object = (LLViewerObject*)object->getParent();
 	}
-	if (object && object == gAgentAvatarp && !gSavedSettings.getBOOL("ClickToWalk"))
+	if (object && object == gAgentAvatarp)
 	{
 		// we left clicked on avatar, switch to focus mode
 		mMouseButtonDown = false;
@@ -436,7 +431,6 @@ BOOL LLToolPie::handleLeftClickPick()
 	//	LLFirstUse::useLeftClickNoHit();
 	/////////
 
-	// Eat the event
 	return LLTool::handleMouseDown(x, y, mask);
 }
 
@@ -545,15 +539,90 @@ void LLToolPie::resetSelection()
 
 void LLToolPie::walkToClickedLocation()
 {
-	if(mAutoPilotDestination) { mAutoPilotDestination->markDead(); }
-	mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE);
-	mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal);
-	mAutoPilotDestination->setPixelSize(5);
-	mAutoPilotDestination->setColor(LLColor4U(170, 210, 190));
-	mAutoPilotDestination->setDuration(3.f);
-
-	LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal;
-	gAgent.startAutoPilotGlobal(pos, std::string(), NULL, NULL, NULL, 0.f, 0.03f, FALSE);
+    if (gAgent.getFlying()							// don't auto-navigate while flying until that works
+        || !gAgentAvatarp
+        || gAgentAvatarp->isSitting())
+    {
+        return;
+    }
+
+    LLPickInfo saved_pick = mPick;
+    mPick = gViewerWindow->pickImmediate(mHoverPick.mMousePt.mX, mHoverPick.mMousePt.mY,
+        FALSE /* ignore transparent */,
+        FALSE /* ignore rigged */,
+        FALSE /* ignore particles */);
+
+    if (mPick.mPickType == LLPickInfo::PICK_OBJECT)
+    {
+        if (mPick.getObject() && mPick.getObject()->isHUDAttachment())
+        {
+            mPick = saved_pick;
+            return;
+        }
+    }
+
+    LLViewerObject* avatar_object = mPick.getObject();
+
+    // get pointer to avatar
+    while (avatar_object && !avatar_object->isAvatar())
+    {
+        avatar_object = (LLViewerObject*)avatar_object->getParent();
+    }
+
+    if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf())
+    {
+        const F64 SELF_CLICK_WALK_DISTANCE = 3.0;
+        // pretend we picked some point a bit in front of avatar
+        mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE;
+    }
+
+    gAgentCamera.setFocusOnAvatar(TRUE, TRUE);
+
+    if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) ||
+        (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero()))
+    {
+        if (mAutoPilotDestination) { mAutoPilotDestination->markDead(); }
+        mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE);
+        mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal);
+        mAutoPilotDestination->setPixelSize(5);
+        mAutoPilotDestination->setColor(LLColor4U(170, 210, 190));
+        mAutoPilotDestination->setDuration(3.f);
+
+        LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal;
+        gAgent.startAutoPilotGlobal(pos, std::string(), NULL, NULL, NULL, 0.f, 0.03f, FALSE);
+        LLFirstUse::notMoving(false);
+        showVisualContextMenuEffect();
+    }
+    else
+    {
+        LL_DEBUGS() << "walk target was "
+            << (mPick.mPosGlobal.isExactlyZero() ? "zero" : "not zero")
+            << ", pick type was " << (mPick.mPickType == LLPickInfo::PICK_LAND ? "land" : "not land")
+            << ", pick object was " << mPick.mObjectID
+            << LL_ENDL;
+        mPick = saved_pick;
+    }
+}
+
+void LLToolPie::teleportToClickedLocation()
+{
+    LLViewerObject* objp = mHoverPick.getObject();
+    LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL;
+
+    bool is_in_world = mHoverPick.mObjectID.notNull() && objp && !objp->isHUDAttachment();
+    bool is_land = mHoverPick.mPickType == LLPickInfo::PICK_LAND;
+    bool pos_non_zero = !mHoverPick.mPosGlobal.isExactlyZero();
+    bool has_touch_handler = (objp && objp->flagHandleTouch()) || (parentp && parentp->flagHandleTouch());
+    bool has_click_action = final_click_action(objp);
+
+    if (pos_non_zero && (is_land || (is_in_world && !has_touch_handler && !has_click_action)))
+    {
+        LLVector3d pos = mHoverPick.mPosGlobal;
+        pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot();
+        gAgent.teleportViaLocationLookAt(pos);
+    }
+    mPick = mHoverPick;
+    showVisualContextMenuEffect();
 }
 
 // When we get object properties after left-clicking on an object
@@ -629,8 +698,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
 		LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL;
 	}
 	else if (!mMouseOutsideSlop 
-		&& mMouseButtonDown 
-		&& gSavedSettings.getBOOL("ClickToWalk"))
+		&& mMouseButtonDown)
 	{
 		S32 delta_x = x - mMouseDownX;
 		S32 delta_y = y - mMouseDownY;
@@ -715,70 +783,10 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
         mDoubleClickTimer.reset();
     }
     LLViewerObject* obj = mPick.getObject();
-	U8 click_action = final_click_action(obj);
 
-	// let media have first pass at click
-	if (handleMediaMouseUp() || LLViewerMediaFocus::getInstance()->getFocus())
-	{
-		mBlockClickToWalk = true;
-	}
 	stopCameraSteering();
 	mMouseButtonDown = false;
 
-	if (click_action == CLICK_ACTION_NONE				// not doing 1-click action
-		&& gSavedSettings.getBOOL("ClickToWalk")		// click to walk enabled
-		&& !gAgent.getFlying()							// don't auto-navigate while flying until that works
-		&& gAgentAvatarp
-		&& !gAgentAvatarp->isSitting()
-		&& !mBlockClickToWalk							// another behavior hasn't cancelled click to walk
-        )
-	{
-        // We may be doing click to walk, but we don't want to use a target on
-        // a transparent object because the user thought they were clicking on
-        // whatever they were seeing through it, so recompute what was clicked on
-        // ignoring transparent objects
-        LLPickInfo savedPick = mPick;
-        mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY,
-                                             FALSE /* ignore transparent */,
-                                             FALSE /* ignore rigged */,
-                                             FALSE /* ignore particles */);
-
-        if (!mPick.mPosGlobal.isExactlyZero()			// valid coordinates for pick
-            && (mPick.mPickType == LLPickInfo::PICK_LAND	// we clicked on land
-                || mPick.mObjectID.notNull()))				// or on an object
-        {
-            // handle special cases of steering picks
-            LLViewerObject* avatar_object = mPick.getObject();
-
-            // get pointer to avatar
-            while (avatar_object && !avatar_object->isAvatar())
-            {
-                avatar_object = (LLViewerObject*)avatar_object->getParent();
-            }
-
-            if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf())
-            {
-                const F64 SELF_CLICK_WALK_DISTANCE = 3.0;
-                // pretend we picked some point a bit in front of avatar
-                mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE;
-            }
-            gAgentCamera.setFocusOnAvatar(TRUE, TRUE);
-            walkToClickedLocation();
-            LLFirstUse::notMoving(false);
-
-            return TRUE;
-        }
-        else
-        {
-            LL_DEBUGS("maint5901") << "walk target was "
-                                   << (mPick.mPosGlobal.isExactlyZero() ? "zero" : "not zero")
-                                   << ", pick type was " << (mPick.mPickType == LLPickInfo::PICK_LAND ? "land" : "not land")
-                                   << ", pick object was " << mPick.mObjectID
-                                   << LL_ENDL;
-            // we didn't click to walk, so restore the original target
-            mPick = savedPick;
-        }
-	}
 	gViewerWindow->setCursor(UI_CURSOR_ARROW);
 	if (hasMouseCapture())
 	{
@@ -788,7 +796,6 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
 	LLToolMgr::getInstance()->clearTransientTool();
 	gAgentCamera.setLookAt(LOOKAT_TARGET_CONVERSATION, obj); // maybe look at object/person clicked on
 
-	mBlockClickToWalk = false;
 	return LLTool::handleMouseUp(x, y, mask);
 }
 
@@ -814,66 +821,13 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask)
 		return TRUE;
 	}
     
-    	if (!mDoubleClickTimer.getStarted() || (mDoubleClickTimer.getElapsedTimeF32() > 0.3f))
+	if (!mDoubleClickTimer.getStarted() || (mDoubleClickTimer.getElapsedTimeF32() > 0.3f))
 	{
 		mDoubleClickTimer.stop();
 		return FALSE;
 	}
 	mDoubleClickTimer.stop();
 
-	if (gSavedSettings.getBOOL("DoubleClickAutoPilot"))
-	{
-        // We may be doing double click to walk, but we don't want to use a target on
-        // a transparent object because the user thought they were clicking on
-        // whatever they were seeing through it, so recompute what was clicked on
-        // ignoring transparent objects
-        LLPickInfo savedPick = mPick;
-        mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY,
-                                             FALSE /* ignore transparent */,
-                                             FALSE /* ignore rigged */,
-                                             FALSE /* ignore particles */);
-
-        if(mPick.mPickType == LLPickInfo::PICK_OBJECT)
-        {
-            if (mPick.getObject() && mPick.getObject()->isHUDAttachment())
-            {
-                mPick = savedPick;
-                return FALSE;
-            }
-        }
-
-		if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) ||
-			(mPick.mObjectID.notNull()  && !mPick.mPosGlobal.isExactlyZero()))
-		{
-			walkToClickedLocation();
-			return TRUE;
-		}
-        else
-        {
-            // restore the original pick for any other purpose
-            mPick = savedPick;
-        }
-	}
-	else if (gSavedSettings.getBOOL("DoubleClickTeleport"))
-	{
-		LLViewerObject* objp = mPick.getObject();
-		LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL;
-
-		bool is_in_world = mPick.mObjectID.notNull() && objp && !objp->isHUDAttachment();
-		bool is_land = mPick.mPickType == LLPickInfo::PICK_LAND;
-		bool pos_non_zero = !mPick.mPosGlobal.isExactlyZero();
-		bool has_touch_handler = (objp && objp->flagHandleTouch()) || (parentp && parentp->flagHandleTouch());
-		bool has_click_action = final_click_action(objp);
-
-		if (pos_non_zero && (is_land || (is_in_world && !has_touch_handler && !has_click_action)))
-		{
-			LLVector3d pos = mPick.mPosGlobal;
-			pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot();
-			gAgent.teleportViaLocationLookAt(pos);
-			return TRUE;
-		}
-	}
-
 	return FALSE;
 }
 
@@ -1405,7 +1359,6 @@ void LLToolPie::VisitHomePage(const LLPickInfo& info)
 void LLToolPie::handleSelect()
 {
 	// tool is reselected when app gets focus, etc.
-	mBlockClickToWalk = true;	
 }
 
 void LLToolPie::handleDeselect()
@@ -1466,7 +1419,7 @@ void LLToolPie::stopCameraSteering()
 
 bool LLToolPie::inCameraSteerMode()
 {
-	return mMouseButtonDown && mMouseOutsideSlop && gSavedSettings.getBOOL("ClickToWalk");
+	return mMouseButtonDown && mMouseOutsideSlop;
 }
 
 // true if x,y outside small box around start_x,start_y
@@ -1917,7 +1870,6 @@ void LLToolPie::startCameraSteering()
 {
 	LLFirstUse::notMoving(false);
 	mMouseOutsideSlop = true;
-	mBlockClickToWalk = true;
 
 	if (gAgentCamera.getFocusOnAvatar())
 	{
diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h
index 6d0e25eaeb..c1c8718f7d 100644
--- a/indra/newview/lltoolpie.h
+++ b/indra/newview/lltoolpie.h
@@ -68,7 +68,7 @@ public:
 	LLObjectSelection*	getLeftClickSelection() { return (LLObjectSelection*)mLeftClickSelection; }
 	void 				resetSelection();
 	void				walkToClickedLocation();
-	void				blockClickToWalk() { mBlockClickToWalk = true; }
+	void				teleportToClickedLocation();
 	void				stopClickToWalk();
 	
 	static void			selectionPropertiesReceived();
diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp
index f1a2b037e2..420980ca56 100644
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -38,6 +38,7 @@
 #include "llmorphview.h"
 #include "llmoveview.h"
 #include "lltoolfocus.h"
+#include "lltoolpie.h"
 #include "llviewerwindow.h"
 #include "llvoavatarself.h"
 #include "llfloatercamera.h"
@@ -565,7 +566,7 @@ void edit_avatar_move_backward( EKeystate s )
 
 void stop_moving( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_DOWN != s  ) return;
 	// stop agent
 	gAgent.setControlFlags(AGENT_CONTROL_STOP);
 
@@ -579,7 +580,8 @@ void start_chat( EKeystate s )
     {
         return; // can't talk, gotta go, kthxbye!
     }
-    
+    if (KEYSTATE_DOWN != s) return;
+
 	// start chat
 	LLFloaterIMNearbyChat::startChat(NULL);
 }
@@ -647,6 +649,19 @@ void toggle_enable_media(EKeystate s)
     LLViewerMedia::setAllMediaEnabled(!pause);
 }
 
+void walk_to(EKeystate s)
+{
+    LL_WARNS() << "processing " << LLSD(s).asString() << LL_ENDL;
+    if (KEYSTATE_DOWN != s) return;
+    LLToolPie::getInstance()->walkToClickedLocation();
+}
+
+void teleport_to(EKeystate s)
+{
+    if (KEYSTATE_DOWN != s) return;
+    LLToolPie::getInstance()->teleportToClickedLocation();
+}
+
 #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);
@@ -692,6 +707,8 @@ REGISTER_KEYBOARD_ACTION("toggle_run", toggle_run);
 REGISTER_KEYBOARD_ACTION("toggle_sit", toggle_sit);
 REGISTER_KEYBOARD_ACTION("toggle_pause_media", toggle_pause_media);
 REGISTER_KEYBOARD_ACTION("toggle_enable_media", toggle_enable_media);
+REGISTER_KEYBOARD_ACTION("teleport_to", teleport_to);
+REGISTER_KEYBOARD_ACTION("walk_to", walk_to);
 #undef REGISTER_KEYBOARD_ACTION
 
 LLViewerKeyboard::LLViewerKeyboard()
@@ -754,7 +771,7 @@ BOOL LLViewerKeyboard::mouseFromString(const std::string& string, EMouseClickTyp
         *mode = CLICK_LEFT;
         return TRUE;
     }
-    else if (string == "DLMB")
+    else if (string == "Double LMB")
     {
         *mode = CLICK_DOUBLELEFT;
         return TRUE;
@@ -1043,24 +1060,44 @@ S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode,
 		it != end_it;
 		++it)
 	{
+        bool processed = false;
         if (!it->key.getValue().empty())
         {
             KEY key;
-            MASK mask;
-            bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;
             LLKeyboard::keyFromString(it->key, &key);
-            LLKeyboard::maskFromString(it->mask, &mask);
-            bindKey(mode, key, mask, ignore, it->command);
-            binding_count++;
+            if (key != KEY_NONE)
+            {
+                MASK mask;
+                bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;
+                LLKeyboard::maskFromString(it->mask, &mask);
+                bindKey(mode, key, mask, ignore, it->command);
+                processed = true;
+            }
+            else
+            {
+                LL_WARNS_ONCE() << "There might be issues in keybindings' file" << LL_ENDL;
+            }
         }
-        else if (it->mouse.isProvided() && !it->mouse.getValue().empty())
+        if (!processed && it->mouse.isProvided() && !it->mouse.getValue().empty())
         {
             EMouseClickType mouse;
-            MASK mask;
-            bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;
             mouseFromString(it->mouse.getValue(), &mouse);
-            LLKeyboard::maskFromString(it->mask, &mask);
-            bindMouse(mode, mouse, mask, ignore, it->command);
+            if (mouse != CLICK_NONE)
+            {
+                MASK mask;
+                bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;
+                LLKeyboard::maskFromString(it->mask, &mask);
+                bindMouse(mode, mouse, mask, ignore, it->command);
+                processed = true;
+            }
+            else
+            {
+                LL_WARNS_ONCE() << "There might be issues in keybindings' file" << LL_ENDL;
+            }
+        }
+        if (processed)
+        {
+            // total
             binding_count++;
         }
 	}
@@ -1259,28 +1296,41 @@ BOOL LLViewerKeyboard::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK ma
 
     if (clicktype != CLICK_NONE)
     {
-        // special case
-        // if UI doesn't handle double click, LMB click is issued, so supres LMB 'down' when doubleclick is set
+        // Special case
+        // If UI doesn't handle double click, LMB click is issued, so supres LMB 'down' when doubleclick is set
         // handle !down as if we are handling doubleclick
-        bool override_lmb = (clicktype == CLICK_LEFT
-            && (mMouseLevel[CLICK_DOUBLELEFT] == MOUSE_STATE_DOWN || mMouseLevel[CLICK_DOUBLELEFT] == MOUSE_STATE_LEVEL));
 
-        if (override_lmb && !down)
+        bool double_click_sp = (clicktype == CLICK_LEFT
+            && (mMouseLevel[CLICK_DOUBLELEFT] != MOUSE_STATE_SILENT)
+            && mMouseLevel[CLICK_LEFT] == MOUSE_STATE_SILENT);
+        if (double_click_sp && !down)
         {
-            // process doubleclick instead
+            // Process doubleclick instead
             clicktype = CLICK_DOUBLELEFT;
         }
 
-        if (override_lmb && down)
+
+        if (double_click_sp && down)
         {
-            // else-supress
+            // Consume click.
+            // Due to handling, double click that is not handled will be immediately followed by LMB click
         }
-        // if UI handled 'down', it should handle 'up' as well
-        // if we handle 'down' not by UI, then we should handle 'up'/'level' regardless of UI
-        else if (handled && mMouseLevel[clicktype] != MOUSE_STATE_SILENT)
+        // If UI handled 'down', it should handle 'up' as well
+        // If we handle 'down' not by UI, then we should handle 'up'/'level' regardless of UI
+        else if (handled)
         {
             // UI handled new 'down' so iterupt whatever state we were in.
-            mMouseLevel[clicktype] = MOUSE_STATE_UP;
+            if (mMouseLevel[clicktype] != MOUSE_STATE_SILENT)
+            {
+                if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN)
+                {
+                    mMouseLevel[clicktype] = MOUSE_STATE_CLICK;
+                }
+                else
+                {
+                    mMouseLevel[clicktype] = MOUSE_STATE_UP;
+                }
+            }
         }
         else if (down)
         {
@@ -1295,10 +1345,17 @@ BOOL LLViewerKeyboard::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK ma
                 mMouseLevel[clicktype] = MOUSE_STATE_DOWN;
             }
         }
-        else
+        else if (mMouseLevel[clicktype] != MOUSE_STATE_SILENT)
         {
             // Released mouse key
-            mMouseLevel[clicktype] = MOUSE_STATE_UP;
+            if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN)
+            {
+                mMouseLevel[clicktype] = MOUSE_STATE_CLICK;
+            }
+            else 
+            {
+                mMouseLevel[clicktype] = MOUSE_STATE_UP;
+            }
         }
     }
 
@@ -1314,6 +1371,7 @@ bool LLViewerKeyboard::scanMouse(const LLMouseBinding *binding, S32 binding_coun
             switch (state)
             {
             case MOUSE_STATE_DOWN:
+            case MOUSE_STATE_CLICK:
                 binding[i].mFunction(KEYSTATE_DOWN);
                 break;
             case MOUSE_STATE_LEVEL:
@@ -1358,7 +1416,7 @@ void LLViewerKeyboard::scanMouse()
                 // mouse doesn't support 'continued' state like keyboard does, so after handling, switch to LEVEL
                 mMouseLevel[i] = MOUSE_STATE_LEVEL;
             }
-            else if (mMouseLevel[i] == MOUSE_STATE_UP)
+            else if (mMouseLevel[i] == MOUSE_STATE_UP || mMouseLevel[i] == MOUSE_STATE_CLICK)
             {
                 mMouseLevel[i] = MOUSE_STATE_SILENT;
             }
diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h
index 3ba033509c..10b16e5fa0 100644
--- a/indra/newview/llviewerkeyboard.h
+++ b/indra/newview/llviewerkeyboard.h
@@ -141,6 +141,7 @@ private:
     enum EMouseState
     {
         MOUSE_STATE_DOWN, // key down this frame
+        MOUSE_STATE_CLICK, // key went up and down in scope of same frame
         MOUSE_STATE_LEVEL, // clicked again fast, or never released
         MOUSE_STATE_UP, // went up this frame
         MOUSE_STATE_SILENT // notified about 'up', do not notify again
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 8ef37b9143..b104b7caca 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -8000,7 +8000,6 @@ BOOL LLViewerMenuHolderGL::hideMenus()
 	
 	if (LLMenuHolderGL::hideMenus())
 	{
-		LLToolPie::instance().blockClickToWalk();
 		handled = TRUE;
 	}
 
-- 
cgit v1.2.3


From 4080969968c5bac301d754e58ff938df6cbdb5a5 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Thu, 26 Sep 2019 22:28:18 +0300
Subject: SL-6109 Conflict resolution

---
 indra/llcommon/llkeybind.cpp                       |  76 +++-
 indra/llcommon/llkeybind.h                         |  19 +-
 indra/llui/llscrolllistcell.cpp                    |  24 +-
 indra/llui/llscrolllistcell.h                      |   2 +
 indra/newview/app_settings/settings.xml            |   2 +-
 indra/newview/llappviewer.cpp                      |  19 +-
 indra/newview/llfloaterpreference.cpp              | 164 ++++---
 indra/newview/llfloaterpreference.h                |   4 +
 indra/newview/llkeyconflict.cpp                    | 128 ++++--
 indra/newview/llkeyconflict.h                      |  42 +-
 indra/newview/lltool.cpp                           |   4 +-
 indra/newview/lltoolpie.cpp                        |  17 +-
 indra/newview/lltoolpie.h                          |   4 +-
 indra/newview/llviewerkeyboard.cpp                 | 473 +++++++++++----------
 indra/newview/llviewerkeyboard.h                   |  10 +-
 indra/newview/llviewerwindow.cpp                   |   8 -
 indra/newview/llvoiceclient.cpp                    |  70 ---
 indra/newview/llvoiceclient.h                      |  10 +-
 .../default/xui/en/panel_preferences_controls.xml  |   5 +-
 19 files changed, 612 insertions(+), 469 deletions(-)

diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp
index 0eca289d4b..ff88a9c9aa 100644
--- a/indra/llcommon/llkeybind.cpp
+++ b/indra/llcommon/llkeybind.cpp
@@ -218,13 +218,17 @@ bool LLKeyBind::isEmpty() const
 
 LLSD LLKeyBind::asLLSD() const
 {
+    S32 last = mData.size() - 1;
+    while (mData[last].empty())
+    {
+        last--;
+    }
+
     LLSD data;
-    for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
+    for (S32 i = 0; i <= last; ++i)
     {
-        if (!iter->isEmpty())
-        {
-            data.append(iter->asLLSD());
-        }
+        // append even if empty to not affect visual representation
+        data.append(mData[i].asLLSD());
     }
     return data;
 }
@@ -280,6 +284,43 @@ bool LLKeyBind::hasKeyData(const LLKeyData& data) const
     return hasKeyData(data.mMouse, data.mKey, data.mMask, data.mIgnoreMasks);
 }
 
+bool LLKeyBind::hasKeyData(U32 index) const
+{
+    return mData.size() > index;
+}
+
+S32 LLKeyBind::findKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const
+{
+    if (mouse != CLICK_NONE || key != KEY_NONE)
+    {
+        for (S32 i = 0; i < mData.size(); ++i)
+        {
+            if (mData[i].mKey == key
+                && mData[i].mMask == mask
+                && mData[i].mMouse == mouse
+                && mData[i].mIgnoreMasks == ignore)
+            {
+                return i;
+            }
+        }
+    }
+    return -1;
+}
+
+S32 LLKeyBind::findKeyData(const LLKeyData& data) const
+{
+    return findKeyData(data.mMouse, data.mKey, data.mMask, data.mIgnoreMasks);
+}
+
+LLKeyData LLKeyBind::getKeyData(U32 index) const
+{
+    if (mData.size() > index)
+    {
+        return mData[index];
+    }
+    return LLKeyData();
+}
+
 bool LLKeyBind::addKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore)
 {
     if (!hasKeyData(mouse, key, mask, ignore))
@@ -344,28 +385,29 @@ void LLKeyBind::replaceKeyData(const LLKeyData& data, U32 index)
             }
         }
     }
-    if (mData.size() > index)
+    if (mData.size() <= index)
     {
-        mData[index] = data;
-    }
-    else
-    {
-        mData.push_back(data);
+        mData.resize(index + 1);
     }
+    mData[index] = data;
 }
 
-bool LLKeyBind::hasKeyData(U32 index) const
+void LLKeyBind::resetKeyData(S32 index)
 {
-    return mData.size() > index;
+    if (mData.size() > index)
+    {
+        mData[index].reset();
+    }
 }
 
-LLKeyData LLKeyBind::getKeyData(U32 index) const
+void LLKeyBind::trimEmpty()
 {
-    if (mData.size() > index)
+    S32 last = mData.size() - 1;
+    while (last >= 0 && mData[last].empty())
     {
-        return mData[index];
+        mData.erase(mData.begin() + last);
+        last--;
     }
-    return LLKeyData();
 }
 
 U32 LLKeyBind::getDataCount()
diff --git a/indra/llcommon/llkeybind.h b/indra/llcommon/llkeybind.h
index 25179a57f3..39cb668aac 100644
--- a/indra/llcommon/llkeybind.h
+++ b/indra/llcommon/llkeybind.h
@@ -74,17 +74,26 @@ public:
     bool canHandleKey(KEY key, MASK mask) const;
     bool canHandleMouse(EMouseClickType mouse, MASK mask) const;
 
-    bool LLKeyBind::hasKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const;
-    bool LLKeyBind::hasKeyData(const LLKeyData& data) const;
+    // contains specified combination
+    bool hasKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const;
+    bool hasKeyData(const LLKeyData& data) const;
+    bool hasKeyData(U32 index) const;
+
+    // index of contained LLKeyData
+    S32 findKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const;
+    S32 findKeyData(const LLKeyData& data) const;
+
+    LLKeyData getKeyData(U32 index) const;
 
     // these methods enshure there will be no repeats
     bool addKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore);
     bool addKeyData(const LLKeyData& data);
     void replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore, U32 index);
     void replaceKeyData(const LLKeyData& data, U32 index);
-    bool hasKeyData(U32 index) const;
-    void clear() { mData.clear(); };
-    LLKeyData getKeyData(U32 index) const;
+    void resetKeyData(S32 index);
+    void clear() { mData.clear(); }
+    // if there any empty LLKeyData in the end of the array, remove them
+    void trimEmpty();
     U32 getDataCount();
 
 private:
diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp
index 0a33ee8878..d6627a6957 100644
--- a/indra/llui/llscrolllistcell.cpp
+++ b/indra/llui/llscrolllistcell.cpp
@@ -196,7 +196,14 @@ LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p)
 void LLScrollListText::highlightText(S32 offset, S32 num_chars)
 {
 	mHighlightOffset = offset;
-	mHighlightCount = num_chars;
+	mHighlightCount = llmax(0, num_chars);
+}
+
+//virtual
+void LLScrollListText::setHighlighted(bool highlighted)
+{
+    mHighlightOffset = 0;
+    mHighlightCount = highlighted ? -1 : 0;
 }
 
 //virtual 
@@ -296,6 +303,7 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col
 
 	if (mHighlightCount > 0)
 	{
+		// Highlight text
 		S32 left = 0;
 		switch(mFontAlignment)
 		{
@@ -314,11 +322,15 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col
 				left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1, 
 				1);
 		mRoundedRectImage->draw(highlight_rect, highlight_color);
-		/*LLRect highlight_rect(left - 2, 
-				mFont->getLineHeight() + 2, 
-				left + getWidth() + 2, 
-				1);
-		mRoundedRectImage->draw(highlight_rect, LLColor4::black);*/
+	}
+	else if (mHighlightCount < 0)
+	{
+		// Highlight whole cell
+		LLRect highlight_rect(0,
+		getHeight(),
+		getWidth() - 1,
+		-1);
+		gl_rect_2d(highlight_rect, LLColor4(0.38f, 0.694f, 0.573f, 0.35f));
 	}
 
 	// Try to draw the entire string
diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h
index 1604a9b1dc..b4bb14bcf1 100644
--- a/indra/llui/llscrolllistcell.h
+++ b/indra/llui/llscrolllistcell.h
@@ -103,6 +103,7 @@ public:
 	virtual BOOL			getVisible() const { return TRUE; }
 	virtual void			setWidth(S32 width) { mWidth = width; }
 	virtual void			highlightText(S32 offset, S32 num_chars) {}
+	virtual void			setHighlighted(bool highlighted) {}
 	virtual BOOL			isText() const { return FALSE; }
 	virtual BOOL			needsToolTip() const { return ! mToolTip.empty(); }
 	virtual void			setColor(const LLColor4&) {}
@@ -140,6 +141,7 @@ public:
 	/*virtual*/ const LLSD getValue() const;
 	/*virtual*/ BOOL	getVisible() const;
 	/*virtual*/ void	highlightText(S32 offset, S32 num_chars);
+	/*virtual*/ void	setHighlighted(bool highlighted);
 
 	/*virtual*/ void	setColor(const LLColor4&);
 	/*virtual*/ BOOL	isText() const;
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index da1e87fda4..15447e7e83 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -8184,7 +8184,7 @@
     <key>PushToTalkButton</key>
     <map>
       <key>Comment</key>
-      <string>Which button or keyboard key is used for push-to-talk</string>
+      <string>(Obsolete)Which button or keyboard key is used for push-to-talk</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index dde7275e8e..97e770a106 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1004,20 +1004,15 @@ bool LLAppViewer::init()
 	gGLManager.getGLInfo(gDebugInfo);
 	gGLManager.printGLInfoString();
 
-	// Load Default bindings
-	std::string key_bindings_file = gDirUtilp->findFile("keys.xml",
-														gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
-														gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
-
-
-	if (!gViewerKeyboard.loadBindingsXML(key_bindings_file))
+	// Load User's bindings
+	std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "keys.xml");
+	if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerKeyboard.loadBindingsXML(key_bindings_file))
 	{
-		std::string key_bindings_file = gDirUtilp->findFile("keys.ini",
-															gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
-															gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
-		if (!gViewerKeyboard.loadBindings(key_bindings_file))
+		// Failed to load custom bindings, try default ones
+		key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "keys.xml");
+		if (!gViewerKeyboard.loadBindingsXML(key_bindings_file))
 		{
-			LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL;
+			LL_ERRS("InitInfo") << "Unable to open default key bindings from" << key_bindings_file << LL_ENDL;
 		}
 	}
 
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 6085c92f49..c0e334795a 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -222,7 +222,11 @@ BOOL LLSetKeyBindDialog::postBuild()
 //virtual
 void LLSetKeyBindDialog::onClose(bool app_quiting)
 {
-    pParent = NULL;
+    if (pParent)
+    {
+        pParent->onCancelKeyBind();
+        pParent = NULL;
+    }
     LLModalDialog::onClose(app_quiting);
 }
 
@@ -269,6 +273,7 @@ BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
         if (pParent)
         {
             pParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
+            pParent = NULL;
         }
         closeFloater();
         return true;
@@ -302,6 +307,7 @@ BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
 	if (pParent)
 	{
         pParent->onSetKeyBind(CLICK_NONE, key, mask, pCheckBox->getValue().asBoolean());
+        pParent = NULL;
 	}
 	closeFloater();
 	return result;
@@ -332,6 +338,7 @@ BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClic
         if (pParent)
         {
             pParent->onSetKeyBind(clicktype, KEY_NONE, mask, pCheckBox->getValue().asBoolean());
+            pParent = NULL;
         }
         result = TRUE;
         closeFloater();
@@ -360,6 +367,7 @@ void LLSetKeyBindDialog::onBlank(void* user_data)
     if (self->pParent)
     {
         self->pParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
+        self->pParent = NULL;
     }
     self->closeFloater();
 }
@@ -372,6 +380,7 @@ void LLSetKeyBindDialog::onDefault(void* user_data)
     if (self->pParent)
     {
         self->pParent->onDefaultKeyBind();
+        self->pParent = NULL;
     }
     self->closeFloater();
 }
@@ -2968,11 +2977,12 @@ LLPanelPreferenceControls::LLPanelPreferenceControls()
     mEditingIndex(-1),
     mEditingColumn(-1),
     mEditingMode(0),
-    mShowKeyDialog(false)
+    mShowKeyDialog(false),
+    mHighlightedCell(NULL)
 {
-    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i)
+    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
     {
-        mConflictHandler[i].setLoadMode((LLKeyConflictHandler::EModes)i);
+        mConflictHandler[i].setLoadMode((LLKeyConflictHandler::ESourceMode)i);
     }
 }
 
@@ -3000,46 +3010,34 @@ BOOL LLPanelPreferenceControls::postBuild()
 // 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)
 {
-    /*S32 column = pControlsTable->getColumnIndexFromOffset(x);
-    LLScrollListItem* item = pControlsTable->hitItem(x, y);
-    static LLScrollListCell* last_cell = NULL;
-    if (item && column > 0)
-    {
-        LLScrollListCell* cell = item->getColumn(column);
-        if (cell)
-        {
-            cell->highlightText(0, CHAR_MAX);
-            if (last_cell != NULL && last_cell !=cell)
-            {
-                last_cell->highlightText(0, 0);
-            }
-            last_cell = cell;
-        }
-    }*/
-
     if (mShowKeyDialog)
     {
-        if (mEditingIndex > 0 && mConflictHandler[mEditingMode].canAssignControl((LLKeyConflictHandler::EControlTypes)mEditingIndex))
+        mShowKeyDialog = false;
+        if (mEditingIndex > 0
+            && mConflictHandler[mEditingMode].canAssignControl((LLKeyConflictHandler::EControlTypes)mEditingIndex))
         {
-            mEditingColumn = pControlsTable->getColumnIndexFromOffset(x);
-
-            if (mEditingColumn >0)
+            LLScrollListItem* item = pControlsTable->getFirstSelected(); // don't use pControlsTable->hitItem(x, y) dur to drift;
+            if (item)
             {
-                LLSetKeyBindDialog* dialog = LLFloaterReg::showTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD(), TRUE);
-                if (dialog)
+                mEditingColumn = pControlsTable->getColumnIndexFromOffset(x);
+                if (mEditingColumn > 0)
                 {
-                    /*if (mConflictHandler[mEditingMode].getLoadedMode() == LLKeyConflictHandler::MODE_GENERAL)
-                    {*/
-                        dialog->setParent(this, DEFAULT_KEY_FILTER);
-                    /*}
-                    else
+                    LLScrollListCell* cell = item->getColumn(mEditingColumn);
+                    if (cell)
                     {
-                        dialog->setParent(this, ALLOW_KEYS | ALLOW_MASK_KEYS);
-                    }*/
+                        LLSetKeyBindDialog* dialog = LLFloaterReg::showTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD(), TRUE);
+                        if (dialog)
+                        {
+                            dialog->setParent(this, DEFAULT_KEY_FILTER);
+                            cell->setHighlighted(true);
+                            mHighlightedCell = cell;
+                            pControlsTable->deselectAllItems();
+                            return TRUE;
+                        }
+                    }
                 }
             }
         }
-        mShowKeyDialog = false;
     }
     return LLPanelPreference::handleHover(x, y, mask);
 }
@@ -3089,7 +3087,7 @@ void LLPanelPreferenceControls::addGroupRow(const std::string &icon, S32 index)
 void LLPanelPreferenceControls::regenerateControls()
 {
     mEditingMode = pKeyModeBox->getValue().asInteger();
-    mConflictHandler[mEditingMode].loadFromSettings((LLKeyConflictHandler::EModes)mEditingMode);
+    mConflictHandler[mEditingMode].loadFromSettings((LLKeyConflictHandler::ESourceMode)mEditingMode);
     populateControlTable();
 }
 
@@ -3097,6 +3095,12 @@ void LLPanelPreferenceControls::populateControlTable()
 {
     pControlsTable->clearRows();
 
+    if (mHighlightedCell)
+    {
+        mHighlightedCell->setHighlighted(false);
+        mHighlightedCell = NULL;
+    }
+
     // todo: subsections need sorting?
     std::string label, control_name;
     LLScrollListCell::Params cell_params;
@@ -3189,20 +3193,50 @@ void LLPanelPreferenceControls::addSeparator()
     }
 }
 
+void LLPanelPreferenceControls::updateTable()
+{
+    std::vector<LLScrollListItem*> list = pControlsTable->getAllData();
+    for (S32 i = 0; i < list.size(); ++i)
+    {
+        S32 value = list[i]->getValue().asInteger();
+        if (value > 0)
+        {
+            LLKeyConflictHandler::EControlTypes control = (LLKeyConflictHandler::EControlTypes)value;
+            LLScrollListCell* cell = list[i]->getColumn(1);
+            cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 0));
+            cell = list[i]->getColumn(2);
+            cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 1));
+            cell = list[i]->getColumn(3);
+            cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 2));
+        }
+    }
+
+    if (mHighlightedCell)
+    {
+        mHighlightedCell->setHighlighted(false);
+        mHighlightedCell = NULL;
+    }
+}
+
 void LLPanelPreferenceControls::apply()
 {
-    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i)
+    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
     {
         if (mConflictHandler[i].hasUnsavedChanges())
         {
             mConflictHandler[i].saveToSettings();
         }
     }
+    if (mHighlightedCell)
+    {
+        mHighlightedCell->setHighlighted(false);
+        mHighlightedCell = NULL;
+    }
 }
 
 void LLPanelPreferenceControls::cancel()
 {
-    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i)
+    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
     {
         if (mConflictHandler[i].hasUnsavedChanges())
         {
@@ -3210,11 +3244,16 @@ void LLPanelPreferenceControls::cancel()
         }
     }
     pControlsTable->clear();
+    if (mHighlightedCell)
+    {
+        mHighlightedCell->setHighlighted(false);
+        mHighlightedCell = NULL;
+    }
 }
 
 void LLPanelPreferenceControls::saveSettings()
 {
-    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i)
+    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
     {
         if (mConflictHandler[i].hasUnsavedChanges())
         {
@@ -3227,6 +3266,11 @@ void LLPanelPreferenceControls::saveSettings()
     {
         regenerateControls();
     }
+    else if (mHighlightedCell)
+    {
+        mHighlightedCell->setHighlighted(false);
+        mHighlightedCell = NULL;
+    }
 }
 
 void LLPanelPreferenceControls::resetDirtyChilds()
@@ -3260,6 +3304,12 @@ void LLPanelPreferenceControls::onListCommit()
     // use coordinates from hover to calculate cell
     mEditingIndex = control;
     mShowKeyDialog = true;
+
+    if (mHighlightedCell)
+    {
+        mHighlightedCell->setHighlighted(false);
+        mHighlightedCell = NULL;
+    }
 }
 
 void LLPanelPreferenceControls::onModeCommit()
@@ -3279,30 +3329,20 @@ void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MAS
 
     pControlsTable->deselectAllItems();
     pControlsTable->selectByValue(mEditingIndex);
-    LLScrollListItem *item = pControlsTable->getFirstSelected();
-    if (item && mEditingColumn > 0)
+    if ( mEditingColumn > 0)
     {
-
         mConflictHandler[mEditingMode].registerControl(control, mEditingColumn - 1, click, key, mask, ignore_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));
     }
 
-    populateControlTable();
+    updateTable();
 }
 
 void LLPanelPreferenceControls::onRestoreDefaults()
 {
-    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i)
+    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
     {
         mConflictHandler[mEditingMode].resetToDefaults();
     }
-    populateControlTable();
 }
 
 void LLPanelPreferenceControls::onDefaultKeyBind()
@@ -3316,16 +3356,20 @@ void LLPanelPreferenceControls::onDefaultKeyBind()
 
     pControlsTable->deselectAllItems();
     pControlsTable->selectByValue(mEditingIndex);
-    LLScrollListItem *item = pControlsTable->getFirstSelected();
-    if (item)
+
+    if (mEditingColumn > 0)
     {
-        LLScrollListCell *cell = item->getColumn(mEditingColumn);
+        mConflictHandler[mEditingMode].resetToDefault(control, mEditingColumn - 1);
+    }
+    updateTable();
+}
 
-        if (mEditingColumn > 0)
-        {
-            mConflictHandler[mEditingMode].resetToDefault(control, mEditingColumn - 1);
-            cell->setValue(mConflictHandler[mEditingMode].getControlString(control, mEditingColumn - 1));
-        }
+void LLPanelPreferenceControls::onCancelKeyBind()
+{
+    if (mHighlightedCell)
+    {
+        mHighlightedCell->setHighlighted(false);
+        mHighlightedCell = NULL;
     }
 }
 
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 1ac0f076d2..513fda96df 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -46,6 +46,7 @@ class LLPanelDebug;
 class LLMessageSystem;
 class LLComboBox;
 class LLScrollListCtrl;
+class LLScrollListCell;
 class LLSliderCtrl;
 class LLSD;
 class LLTextBox;
@@ -313,15 +314,18 @@ public:
 	void onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore_mask);
 	void onRestoreDefaults();
 	void onDefaultKeyBind();
+	void onCancelKeyBind();
 
 private:
 	void addGroupRow(const std::string &icon, S32 index);
 	void regenerateControls();
 	void populateControlTable();
 	void addSeparator();
+	void updateTable();
 
 	LLScrollListCtrl* pControlsTable;
 	LLComboBox *pKeyModeBox;
+	LLScrollListCell *mHighlightedCell;
 	LLKeyConflictHandler mConflictHandler[LLKeyConflictHandler::MODE_COUNT];
 	S32 mEditingIndex;
 	S32 mEditingColumn;
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index 87ea408a6a..66d420369e 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -105,8 +105,8 @@ static const std::string typetostring[LLKeyConflictHandler::CONTROL_NUM_INDICES]
     "control_mediacontent",
     "toggle_pause_media",
     "toggle_enable_media",
-    "control_voice",
-    "control_toggle_voice",
+    "voice_follow_key",
+    "toggle_voice",
     "start_chat",
     "start_gesture",
     "control_reserved",
@@ -167,6 +167,8 @@ static const control_enum_t command_to_key =
     { "toggle_enable_media", LLKeyConflictHandler::CONTROL_ENABLE_MEDIA },
     { "walk_to", LLKeyConflictHandler::CONTROL_MOVETO },
     { "teleport_to", LLKeyConflictHandler::CONTROL_TELEPORTTO },
+    { "toggle_voice", LLKeyConflictHandler::CONTROL_TOGGLE_VOICE },
+    { "voice_follow_key", LLKeyConflictHandler::CONTROL_VOICE },
 };
 
 
@@ -256,19 +258,9 @@ EMouseClickType mouse_from_string(const std::string& input)
 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)
+LLKeyConflictHandler::LLKeyConflictHandler(ESourceMode mode)
     : mHasUnsavedChanges(false),
     mLoadMode(mode)
 {
@@ -305,16 +297,26 @@ bool LLKeyConflictHandler::canAssignControl(EControlTypes control_type)
     return false;
 }
 
-void LLKeyConflictHandler::registerControl(EControlTypes control_type, U32 index, EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask)
+bool LLKeyConflictHandler::registerControl(EControlTypes control_type, U32 index, EMouseClickType mouse, KEY key, MASK mask, bool ignore_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, ignore_mask, index);
-
-    mHasUnsavedChanges = true;
+    LLKeyData data(mouse, key, mask, ignore_mask);
+    if (type_data.mKeyBind.getKeyData(index) == data)
+    {
+        return true;
+    }
+    if (removeConflicts(data, type_data.mConflictMask))
+    {
+        type_data.mKeyBind.replaceKeyData(data, index);
+        mHasUnsavedChanges = true;
+        return true;
+    }
+    // control already in use/blocked
+    return false;
 }
 
 LLKeyData LLKeyConflictHandler::getControl(EControlTypes control_type, U32 index)
@@ -391,7 +393,7 @@ void  LLKeyConflictHandler::loadFromSettings(const LLViewerKeyboard::KeyMode& ke
     }
 }
 
-void LLKeyConflictHandler::loadFromSettings(const EModes &load_mode, const std::string &filename, control_map_t *destination)
+void LLKeyConflictHandler::loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination)
 {
     if (filename.empty())
     {
@@ -442,7 +444,7 @@ void LLKeyConflictHandler::loadFromSettings(const EModes &load_mode, const std::
     }
 }
 
-void  LLKeyConflictHandler::loadFromSettings(EModes load_mode)
+void  LLKeyConflictHandler::loadFromSettings(ESourceMode load_mode)
 {
     mControlsMap.clear();
     mDefaultsMap.clear();
@@ -571,6 +573,11 @@ void  LLKeyConflictHandler::saveToSettings()
             control_map_t::iterator end = mControlsMap.end();
             for (; iter != end; ++iter)
             {
+                // By default xml have (had) up to 6 elements per function
+                // eventually it will be cleaned up and UI will only shows 3 per function,
+                // so make sure to cleanup.
+                // Also this helps in keeping file small.
+                iter->second.mKeyBind.trimEmpty();
                 U32 size = iter->second.mKeyBind.getDataCount();
                 for (U32 i = 0; i < size; ++i)
                 {
@@ -683,10 +690,16 @@ LLKeyData LLKeyConflictHandler::getDefaultControl(EControlTypes control_type, U3
 void LLKeyConflictHandler::resetToDefault(EControlTypes control_type, U32 index)
 {
     LLKeyData data = getDefaultControl(control_type, index);
-    mControlsMap[control_type].setKeyData(data, index);
+
+    if (data != mControlsMap[control_type].getKeyData(index))
+    {
+        // reset controls that might have been switched to our current control
+        removeConflicts(data, mControlsMap[control_type].mConflictMask);
+        mControlsMap[control_type].setKeyData(data, index);
+    }
 }
 
-void LLKeyConflictHandler::resetToDefault(EControlTypes control_type)
+void LLKeyConflictHandler::resetToDefaultAndResolve(EControlTypes control_type, bool ignore_conflicts)
 {
     if (mLoadMode == MODE_GENERAL)
     {
@@ -694,7 +707,15 @@ void LLKeyConflictHandler::resetToDefault(EControlTypes control_type)
         LLControlVariablePtr var = gSavedSettings.getControl(name);
         if (var)
         {
-            mControlsMap[control_type].mKeyBind = LLKeyBind(var->getDefault());
+            LLKeyBind bind(var->getDefault());
+            if (!ignore_conflicts)
+            {
+                for (S32 i = 0; i < bind.getDataCount(); ++i)
+                {
+                    removeConflicts(bind.getKeyData(i), mControlsMap[control_type].mConflictMask);
+                }
+            }
+            mControlsMap[control_type].mKeyBind = bind;
         }
         else
         {
@@ -706,6 +727,13 @@ void LLKeyConflictHandler::resetToDefault(EControlTypes control_type)
         control_map_t::iterator iter = mDefaultsMap.find(control_type);
         if (iter != mDefaultsMap.end())
         {
+            if (!ignore_conflicts)
+            {
+                for (S32 i = 0; i < iter->second.mKeyBind.getDataCount(); ++i)
+                {
+                    removeConflicts(iter->second.mKeyBind.getKeyData(i), mControlsMap[control_type].mConflictMask);
+                }
+            }
             mControlsMap[control_type].mKeyBind = iter->second.mKeyBind;
         }
         else
@@ -715,7 +743,13 @@ void LLKeyConflictHandler::resetToDefault(EControlTypes control_type)
     }
 }
 
-void LLKeyConflictHandler::resetToDefaults(EModes mode)
+void LLKeyConflictHandler::resetToDefault(EControlTypes control_type)
+{
+    // reset specific binding without ignoring conflicts
+    resetToDefaultAndResolve(control_type, false);
+}
+
+void LLKeyConflictHandler::resetToDefaults(ESourceMode mode)
 {
     if (mode == MODE_GENERAL)
     {
@@ -735,7 +769,7 @@ void LLKeyConflictHandler::resetToDefaults(EModes mode)
                 break;
             default:
             {
-                resetToDefault(type);
+                resetToDefaultAndResolve(type, true);
                 break;
             }
             }
@@ -785,9 +819,53 @@ void LLKeyConflictHandler::resetKeyboardBindings()
     gViewerKeyboard.loadBindingsXML(filename);
 }
 
-void LLKeyConflictHandler::generatePlaceholders(EModes load_mode)
+void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode)
 {
+    // These controls are meant to cause conflicts when user tries to assign same control somewhere else
+    // also this can be used to pre-record controls that should not conflict or to assign conflict groups/masks
+    /*registerTemporaryControl(CONTROL_RESERVED_MENU, CLICK_RIGHT, KEY_NONE, MASK_NONE, 0);
+    registerTemporaryControl(CONTROL_DELETE, CLICK_NONE, KEY_DELETE, MASK_NONE, 0);*/
+}
 
+bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, const U32 &conlict_mask)
+{
+    if (conlict_mask == CONFLICT_NOTHING)
+    {
+        // Can't conflict
+        return true;
+    }
+    std::map<EControlTypes, S32> conflict_list;
+    control_map_t::iterator cntrl_iter = mControlsMap.begin();
+    control_map_t::iterator cntrl_end = mControlsMap.end();
+    for (; cntrl_iter != cntrl_end; ++cntrl_iter)
+    {
+        S32 index = cntrl_iter->second.mKeyBind.findKeyData(data);
+        if (index >= 0
+            && cntrl_iter->second.mConflictMask != CONFLICT_NOTHING
+            && (cntrl_iter->second.mConflictMask & conlict_mask) != 0)
+        {
+            if (cntrl_iter->second.mAssignable)
+            {
+                // Potentially we can have multiple conflict flags conflicting
+                // including unassignable keys.
+                // So record the conflict and find all others before doing any changes.
+                // Assume that there is only one conflict per bind
+                conflict_list[cntrl_iter->first] = index;
+            }
+            else
+            {
+                return false;
+            }
+        }
+    }
+
+    std::map<EControlTypes, S32>::iterator cnflct_iter = conflict_list.begin();
+    std::map<EControlTypes, S32>::iterator cnflct_end = conflict_list.end();
+    for (; cnflct_iter != cnflct_end; ++cnflct_iter)
+    {
+        mControlsMap[cnflct_iter->first].mKeyBind.resetKeyData(cnflct_iter->second);
+    }
+    return true;
 }
 
 void LLKeyConflictHandler::registerTemporaryControl(EControlTypes control_type, EMouseClickType mouse, KEY key, MASK mask, U32 conflict_mask)
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index b0f99e2d0c..00fbe18863 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -34,7 +34,7 @@
 class LLKeyConflict
 {
 public:
-    LLKeyConflict() : mAssignable(true), mConflictMask(0) {} //temporary assignable, don't forget to change once all keys are recorded
+    LLKeyConflict() : mAssignable(true), mConflictMask(U32_MAX) {} //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)
@@ -55,26 +55,20 @@ class LLKeyConflictHandler
 {
 public:
 
-    enum EModes // partially repeats e_keyboard_mode
+    enum ESourceMode // partially repeats e_keyboard_mode
     {
         MODE_FIRST_PERSON,
         MODE_THIRD_PERSON,
         MODE_EDIT,
         MODE_EDIT_AVATAR,
         MODE_SITTING,
-        MODE_GENERAL,
+        MODE_GENERAL, // for settings from saved settings
         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
-    };
+    const U32 CONFLICT_NOTHING = 0;
+    // at the moment this just means that key will conflict with everything that is identical
+    const U32 CONFLICT_ANY = U32_MAX;
 
     // todo, unfortunately will have to remove this and use map/array of strings
     enum EControlTypes
@@ -142,7 +136,7 @@ public:
         CONTROL_MEDIACONTENT, // Group control, for visual representation
         CONTROL_PAUSE_MEDIA, // Play pause
         CONTROL_ENABLE_MEDIA, // Play stop
-        CONTROL_VOICE, // Keep pressing for it to be ON
+        CONTROL_VOICE, // Keep pressing for voice 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
@@ -158,14 +152,14 @@ public:
     // Note: missed selection and edition commands (would be really nice to go through selection via MB4/5 or wheel)
 
     LLKeyConflictHandler();
-    LLKeyConflictHandler(EModes mode);
+    LLKeyConflictHandler(ESourceMode 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, bool ignore_mask); //todo: return conflicts?
+    bool registerControl(EControlTypes control_type, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask, bool ignore_mask); //todo: return conflicts?
 
     LLKeyData getControl(EControlTypes control_type, U32 data_index);
 
@@ -175,7 +169,7 @@ public:
 
 
     // Drops any changes loads controls with ones from 'saved settings' or from xml
-    void loadFromSettings(EModes load_mode);
+    void loadFromSettings(ESourceMode load_mode);
     // Saves settings to 'saved settings' or to xml
     void saveToSettings();
 
@@ -190,26 +184,28 @@ public:
     void clear();
 
     bool hasUnsavedChanges() { return mHasUnsavedChanges; }
-    void setLoadMode(EModes mode) { mLoadMode = mode; }
-    EModes getLoadMode() { return mLoadMode; }
-    // todo: conflict search
+    void setLoadMode(ESourceMode mode) { mLoadMode = mode; }
+    ESourceMode getLoadMode() { return mLoadMode; }
 
 private:
-    void resetToDefaults(EModes mode);
+    void resetToDefaultAndResolve(EControlTypes control_type, bool ignore_conflicts);
+    void resetToDefaults(ESourceMode mode);
 
     // 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<EControlTypes, LLKeyConflict> 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 loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination);
     void resetKeyboardBindings();
-    void generatePlaceholders(EModes load_mode); //E.x. non-assignable values
+    void generatePlaceholders(ESourceMode load_mode); //E.x. non-assignable values
+    // returns false in case user is trying to reuse control that can't be reassigned
+    bool removeConflicts(const LLKeyData &data, const U32 &conlict_mask);
 
     control_map_t mControlsMap;
     control_map_t mDefaultsMap;
     bool mHasUnsavedChanges;
-    EModes mLoadMode;
+    ESourceMode mLoadMode;
 };
 
 
diff --git a/indra/newview/lltool.cpp b/indra/newview/lltool.cpp
index e2ab450d8c..5235914c34 100644
--- a/indra/newview/lltool.cpp
+++ b/indra/newview/lltool.cpp
@@ -83,8 +83,8 @@ BOOL LLTool::handleMouseDown(S32 x, S32 y, MASK mask)
 		LL_INFOS() << "LLTool left mouse down" << LL_ENDL;
 	}
 	// by default, didn't handle it
+	// AGENT_CONTROL_LBUTTON_DOWN is handled by scanMouse() and scanKey()
 	// LL_INFOS() << "LLTool::handleMouseDown" << LL_ENDL;
-	gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN);
 	return FALSE;
 }
 
@@ -95,8 +95,8 @@ BOOL LLTool::handleMouseUp(S32 x, S32 y, MASK mask)
 		LL_INFOS() << "LLTool left mouse up" << LL_ENDL;
 	}
 	// by default, didn't handle it
+	// AGENT_CONTROL_LBUTTON_UP is handled by scanMouse() and scanKey()
 	// LL_INFOS() << "LLTool::handleMouseUp" << LL_ENDL;
-	gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP);
 	return TRUE;
 }
 
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 4edfd7fb39..dc9c0edc0c 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -537,13 +537,13 @@ void LLToolPie::resetSelection()
 	mClickAction = 0;
 }
 
-void LLToolPie::walkToClickedLocation()
+bool LLToolPie::walkToClickedLocation()
 {
     if (gAgent.getFlying()							// don't auto-navigate while flying until that works
         || !gAgentAvatarp
         || gAgentAvatarp->isSitting())
     {
-        return;
+        return false;
     }
 
     LLPickInfo saved_pick = mPick;
@@ -557,7 +557,7 @@ void LLToolPie::walkToClickedLocation()
         if (mPick.getObject() && mPick.getObject()->isHUDAttachment())
         {
             mPick = saved_pick;
-            return;
+            return false;
         }
     }
 
@@ -592,6 +592,7 @@ void LLToolPie::walkToClickedLocation()
         gAgent.startAutoPilotGlobal(pos, std::string(), NULL, NULL, NULL, 0.f, 0.03f, FALSE);
         LLFirstUse::notMoving(false);
         showVisualContextMenuEffect();
+        return true;
     }
     else
     {
@@ -601,10 +602,12 @@ void LLToolPie::walkToClickedLocation()
             << ", pick object was " << mPick.mObjectID
             << LL_ENDL;
         mPick = saved_pick;
+        return false;
     }
+    return true;
 }
 
-void LLToolPie::teleportToClickedLocation()
+bool LLToolPie::teleportToClickedLocation()
 {
     LLViewerObject* objp = mHoverPick.getObject();
     LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL;
@@ -620,9 +623,11 @@ void LLToolPie::teleportToClickedLocation()
         LLVector3d pos = mHoverPick.mPosGlobal;
         pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot();
         gAgent.teleportViaLocationLookAt(pos);
+        mPick = mHoverPick;
+        showVisualContextMenuEffect();
+        return true;
     }
-    mPick = mHoverPick;
-    showVisualContextMenuEffect();
+    return false;
 }
 
 // When we get object properties after left-clicking on an object
diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h
index c1c8718f7d..60159594c9 100644
--- a/indra/newview/lltoolpie.h
+++ b/indra/newview/lltoolpie.h
@@ -67,8 +67,8 @@ public:
 	LLViewerObject*		getClickActionObject() { return mClickActionObject; }
 	LLObjectSelection*	getLeftClickSelection() { return (LLObjectSelection*)mLeftClickSelection; }
 	void 				resetSelection();
-	void				walkToClickedLocation();
-	void				teleportToClickedLocation();
+	bool				walkToClickedLocation();
+	bool				teleportToClickedLocation();
 	void				stopClickToWalk();
 	
 	static void			selectionPropertiesReceived();
diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp
index 420980ca56..9755d3444a 100644
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -26,19 +26,21 @@
 
 #include "llviewerprecompiledheaders.h"
 
+#include "llviewerkeyboard.h"
+
 #include "llappviewer.h"
 #include "llfloaterreg.h"
-#include "llviewerkeyboard.h"
 #include "llmath.h"
 #include "llagent.h"
 #include "llagentcamera.h"
 #include "llfloaterimnearbychat.h"
-#include "llviewercontrol.h"
 #include "llfocusmgr.h"
+#include "llkeybind.h" // LLKeyData
 #include "llmorphview.h"
 #include "llmoveview.h"
 #include "lltoolfocus.h"
 #include "lltoolpie.h"
+#include "llviewercontrol.h"
 #include "llviewerwindow.h"
 #include "llvoavatarself.h"
 #include "llfloatercamera.h"
@@ -55,21 +57,23 @@ const F32 NUDGE_TIME = 0.25f;  // in seconds
 const S32 NUDGE_FRAMES = 2;
 const F32 ORBIT_NUDGE_RATE = 0.05f;  // fraction of normal speed
 
+const LLKeyData agent_control_lbutton(CLICK_LEFT, KEY_NONE, MASK_NONE, true);
+
 struct LLKeyboardActionRegistry 
-:	public LLRegistrySingleton<std::string, boost::function<void (EKeystate keystate)>, LLKeyboardActionRegistry>
+:	public LLRegistrySingleton<std::string, boost::function<bool (EKeystate keystate)>, LLKeyboardActionRegistry>
 {
 	LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry);
 };
 
 LLViewerKeyboard gViewerKeyboard;
 
-void agent_jump( EKeystate s )
+bool agent_jump( EKeystate s )
 {
 	static BOOL first_fly_attempt(TRUE);
 	if (KEYSTATE_UP == s)
 	{
 		first_fly_attempt = TRUE;
-		return;
+		return true;
 	}
 	F32 time = gKeyboard->getCurKeyElapsedTime();
 	S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
@@ -87,12 +91,14 @@ void agent_jump( EKeystate s )
 		first_fly_attempt = FALSE;
 		gAgent.moveUp(1);
 	}
+	return true;
 }
 
-void agent_push_down( EKeystate s )
+bool agent_push_down( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgent.moveUp(-1);
+	return true;
 }
 
 static void agent_check_temporary_run(LLAgent::EDoubleTapRunMode mode)
@@ -152,11 +158,11 @@ static void agent_push_forwardbackward( EKeystate s, S32 direction, LLAgent::EDo
 	}
 }
 
-void camera_move_forward( EKeystate s );
+bool camera_move_forward( EKeystate s );
 
-void agent_push_forward( EKeystate s )
+bool agent_push_forward( EKeystate s )
 {
-	if(gAgent.isMovementLocked()) return;
+	if(gAgent.isMovementLocked()) return true;
 
 	//in free camera control mode we need to intercept keyboard events for avatar movements
 	if (LLFloaterCamera::inFreeCameraMode())
@@ -167,13 +173,14 @@ void agent_push_forward( EKeystate s )
 	{
 		agent_push_forwardbackward(s, 1, LLAgent::DOUBLETAP_FORWARD);
 	}
+	return true;
 }
 
-void camera_move_backward( EKeystate s );
+bool camera_move_backward( EKeystate s );
 
-void agent_push_backward( EKeystate s )
+bool agent_push_backward( EKeystate s )
 {
-	if(gAgent.isMovementLocked()) return;
+	if(gAgent.isMovementLocked()) return true;
 
 	//in free camera control mode we need to intercept keyboard events for avatar movements
 	if (LLFloaterCamera::inFreeCameraMode())
@@ -188,6 +195,7 @@ void agent_push_backward( EKeystate s )
 	{
 		agent_push_forwardbackward(s, -1, LLAgent::DOUBLETAP_BACKWARD);
 	}
+	return true;
 }
 
 static void agent_slide_leftright( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode )
@@ -208,31 +216,33 @@ static void agent_slide_leftright( EKeystate s, S32 direction, LLAgent::EDoubleT
 }
 
 
-void agent_slide_left( EKeystate s )
+bool agent_slide_left( EKeystate s )
 {
-	if(gAgent.isMovementLocked()) return;
+	if(gAgent.isMovementLocked()) return true;
 	agent_slide_leftright(s, 1, LLAgent::DOUBLETAP_SLIDELEFT);
+	return true;
 }
 
 
-void agent_slide_right( EKeystate s )
+bool agent_slide_right( EKeystate s )
 {
-	if(gAgent.isMovementLocked()) return;
+	if(gAgent.isMovementLocked()) return true;
 	agent_slide_leftright(s, -1, LLAgent::DOUBLETAP_SLIDERIGHT);
+	return true;
 }
 
-void camera_spin_around_cw( EKeystate s );
+bool camera_spin_around_cw( EKeystate s );
 
-void agent_turn_left( EKeystate s )
+bool agent_turn_left(EKeystate s)
 {
 	//in free camera control mode we need to intercept keyboard events for avatar movements
 	if (LLFloaterCamera::inFreeCameraMode())
 	{
 		camera_spin_around_cw(s);
-		return;
+		return true;
 	}
 
-	if(gAgent.isMovementLocked()) return;
+	if(gAgent.isMovementLocked()) return false;
 
 	if (LLToolCamera::getInstance()->mouseSteerMode())
 	{
@@ -244,25 +254,26 @@ void agent_turn_left( EKeystate s )
 		{
 			// Check temporary running. In case user released 'left' key with shift already released.
 			agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDELEFT);
-			return;
+			return true;
 		}
 		F32 time = gKeyboard->getCurKeyElapsedTime();
 		gAgent.moveYaw( LLFloaterMove::getYawRate( time ) );
 	}
+	return true;
 }
 
-void camera_spin_around_ccw( EKeystate s );
+bool camera_spin_around_ccw( EKeystate s );
 
-void agent_turn_right( EKeystate s )
+bool agent_turn_right( EKeystate s )
 {
 	//in free camera control mode we need to intercept keyboard events for avatar movements
 	if (LLFloaterCamera::inFreeCameraMode())
 	{
 		camera_spin_around_ccw(s);
-		return;
+		return true;
 	}
 
-	if(gAgent.isMovementLocked()) return;
+	if(gAgent.isMovementLocked()) return false;
 
 	if (LLToolCamera::getInstance()->mouseSteerMode())
 	{
@@ -274,35 +285,39 @@ void agent_turn_right( EKeystate s )
 		{
 			// Check temporary running. In case user released 'right' key with shift already released.
 			agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDERIGHT);
-			return;
+			return true;
 		}
 		F32 time = gKeyboard->getCurKeyElapsedTime();
 		gAgent.moveYaw( -LLFloaterMove::getYawRate( time ) );
 	}
+	return true;
 }
 
-void agent_look_up( EKeystate s )
+bool agent_look_up( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgent.movePitch(-1);
 	//gAgent.rotate(-2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
+	return true;
 }
 
 
-void agent_look_down( EKeystate s )
+bool agent_look_down( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgent.movePitch(1);
 	//gAgent.rotate(2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
+	return true;
 }
 
-void agent_toggle_fly( EKeystate s )
+bool agent_toggle_fly( EKeystate s )
 {
 	// Only catch the edge
 	if (KEYSTATE_DOWN == s )
 	{
 		LLAgent::toggleFlying();
 	}
+	return true;
 }
 
 F32 get_orbit_rate()
@@ -320,24 +335,26 @@ F32 get_orbit_rate()
 	}
 }
 
-void camera_spin_around_ccw( EKeystate s )
+bool camera_spin_around_ccw( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
+	return true;
 }
 
 
-void camera_spin_around_cw( EKeystate s )
+bool camera_spin_around_cw( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setOrbitRightKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_spin_around_ccw_sitting( EKeystate s )
+bool camera_spin_around_ccw_sitting( EKeystate s )
 {
-	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT ) return;
+	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT ) return true;
 	if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning())
 	{
 		//send keystrokes, but do not change camera
@@ -348,12 +365,13 @@ void camera_spin_around_ccw_sitting( EKeystate s )
 		//change camera but do not send keystrokes
 		gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
 	}
+	return true;
 }
 
 
-void camera_spin_around_cw_sitting( EKeystate s )
+bool camera_spin_around_cw_sitting( EKeystate s )
 {
-	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT ) return;
+	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT ) return true;
 	if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning())
 	{
 		//send keystrokes, but do not change camera
@@ -364,27 +382,30 @@ void camera_spin_around_cw_sitting( EKeystate s )
 		//change camera but do not send keystrokes
 		gAgentCamera.setOrbitRightKey( get_orbit_rate() );
 	}
+	return true;
 }
 
 
-void camera_spin_over( EKeystate s )
+bool camera_spin_over( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setOrbitUpKey( get_orbit_rate() );
+	return true;
 }
 
 
-void camera_spin_under( EKeystate s )
+bool camera_spin_under( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setOrbitDownKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_spin_over_sitting( EKeystate s )
+bool camera_spin_over_sitting( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	if (gAgent.upGrabbed() || gAgentCamera.sitCameraEnabled())
 	{
 		//send keystrokes, but do not change camera
@@ -395,12 +416,13 @@ void camera_spin_over_sitting( EKeystate s )
 		//change camera but do not send keystrokes
 		gAgentCamera.setOrbitUpKey( get_orbit_rate() );
 	}
+	return true;
 }
 
 
-void camera_spin_under_sitting( EKeystate s )
+bool camera_spin_under_sitting( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	if (gAgent.downGrabbed() || gAgentCamera.sitCameraEnabled())
 	{
 		//send keystrokes, but do not change camera
@@ -411,26 +433,29 @@ void camera_spin_under_sitting( EKeystate s )
 		//change camera but do not send keystrokes
 		gAgentCamera.setOrbitDownKey( get_orbit_rate() );
 	}
+	return true;
 }
 
-void camera_move_forward( EKeystate s )
+bool camera_move_forward( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setOrbitInKey( get_orbit_rate() );
+	return true;
 }
 
 
-void camera_move_backward( EKeystate s )
+bool camera_move_backward( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setOrbitOutKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_move_forward_sitting( EKeystate s )
+bool camera_move_forward_sitting( EKeystate s )
 {
-	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD ) return;
+	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD ) return true;
 	if (gAgent.forwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun()))
 	{
 		agent_push_forward(s);
@@ -439,12 +464,13 @@ void camera_move_forward_sitting( EKeystate s )
 	{
 		gAgentCamera.setOrbitInKey( get_orbit_rate() );
 	}
+	return true;
 }
 
 
-void camera_move_backward_sitting( EKeystate s )
+bool camera_move_backward_sitting( EKeystate s )
 {
-	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD ) return;
+	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD ) return true;
 
 	if (gAgent.backwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun()))
 	{
@@ -454,139 +480,156 @@ void camera_move_backward_sitting( EKeystate s )
 	{
 		gAgentCamera.setOrbitOutKey( get_orbit_rate() );
 	}
+	return true;
 }
 
-void camera_pan_up( EKeystate s )
+bool camera_pan_up( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setPanUpKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_pan_down( EKeystate s )
+bool camera_pan_down( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setPanDownKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_pan_left( EKeystate s )
+bool camera_pan_left( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setPanLeftKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_pan_right( EKeystate s )
+bool camera_pan_right( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setPanRightKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_pan_in( EKeystate s )
+bool camera_pan_in( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setPanInKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_pan_out( EKeystate s )
+bool camera_pan_out( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setPanOutKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_move_forward_fast( EKeystate s )
+bool camera_move_forward_fast( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setOrbitInKey(2.5f);
+	return true;
 }
 
-void camera_move_backward_fast( EKeystate s )
+bool camera_move_backward_fast( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setOrbitOutKey(2.5f);
+	return true;
 }
 
 
-void edit_avatar_spin_ccw( EKeystate s )
+bool edit_avatar_spin_ccw( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gMorphView->setCameraDrivenByKeys( TRUE );
 	gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
 	//gMorphView->orbitLeft( get_orbit_rate() );
+	return true;
 }
 
 
-void edit_avatar_spin_cw( EKeystate s )
+bool edit_avatar_spin_cw( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gMorphView->setCameraDrivenByKeys( TRUE );
 	gAgentCamera.setOrbitRightKey( get_orbit_rate() );
 	//gMorphView->orbitRight( get_orbit_rate() );
+	return true;
 }
 
-void edit_avatar_spin_over( EKeystate s )
+bool edit_avatar_spin_over( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gMorphView->setCameraDrivenByKeys( TRUE );
 	gAgentCamera.setOrbitUpKey( get_orbit_rate() );
 	//gMorphView->orbitUp( get_orbit_rate() );
+	return true;
 }
 
 
-void edit_avatar_spin_under( EKeystate s )
+bool edit_avatar_spin_under( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gMorphView->setCameraDrivenByKeys( TRUE );
 	gAgentCamera.setOrbitDownKey( get_orbit_rate() );
 	//gMorphView->orbitDown( get_orbit_rate() );
+	return true;
 }
 
-void edit_avatar_move_forward( EKeystate s )
+bool edit_avatar_move_forward( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gMorphView->setCameraDrivenByKeys( TRUE );
 	gAgentCamera.setOrbitInKey( get_orbit_rate() );
 	//gMorphView->orbitIn();
+	return true;
 }
 
 
-void edit_avatar_move_backward( EKeystate s )
+bool edit_avatar_move_backward( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gMorphView->setCameraDrivenByKeys( TRUE );
 	gAgentCamera.setOrbitOutKey( get_orbit_rate() );
 	//gMorphView->orbitOut();
+	return true;
 }
 
-void stop_moving( EKeystate s )
+bool stop_moving( EKeystate s )
 {
-	if( KEYSTATE_DOWN != s  ) return;
+	if( KEYSTATE_DOWN != s  ) return true;
 	// stop agent
 	gAgent.setControlFlags(AGENT_CONTROL_STOP);
 
 	// cancel autopilot
 	gAgent.stopAutoPilot();
+	return true;
 }
 
-void start_chat( EKeystate s )
+bool start_chat( EKeystate s )
 {
     if (LLAppViewer::instance()->quitRequested())
     {
-        return; // can't talk, gotta go, kthxbye!
+        return true; // can't talk, gotta go, kthxbye!
     }
-    if (KEYSTATE_DOWN != s) return;
+    if (KEYSTATE_DOWN != s) return true;
 
 	// start chat
 	LLFloaterIMNearbyChat::startChat(NULL);
+	return true;
 }
 
-void start_gesture( EKeystate s )
+bool start_gesture( EKeystate s )
 {
 	LLUICtrl* focus_ctrlp = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
 	if (KEYSTATE_UP == s &&
@@ -603,11 +646,12 @@ void start_gesture( EKeystate s )
  			LLFloaterIMNearbyChat::startChat(NULL);
  		}
 	}
+	return true;
 }
 
-void toggle_run(EKeystate s)
+bool toggle_run(EKeystate s)
 {
-    if (KEYSTATE_DOWN != s) return;
+    if (KEYSTATE_DOWN != s) return true;
     bool run = gAgent.getAlwaysRun();
     if (run)
     {
@@ -620,11 +664,12 @@ void toggle_run(EKeystate s)
         gAgent.setRunning();
     }
     gAgent.sendWalkRun(!run);
+	return true;
 }
 
-void toggle_sit(EKeystate s)
+bool toggle_sit(EKeystate s)
 {
-    if (KEYSTATE_DOWN != s) return;
+    if (KEYSTATE_DOWN != s) return true;
     if (gAgent.isSitting())
     {
         gAgent.standUp();
@@ -633,33 +678,75 @@ void toggle_sit(EKeystate s)
     {
         gAgent.sitDown();
     }
+	return true;
 }
 
-void toggle_pause_media(EKeystate s) // analogue of play/pause button in top bar
+bool toggle_pause_media(EKeystate s) // analogue of play/pause button in top bar
 {
-    if (KEYSTATE_DOWN != s) return;
+    if (KEYSTATE_DOWN != s) return true;
     bool pause = LLViewerMedia::isAnyMediaPlaying();
     LLViewerMedia::setAllMediaPaused(pause);
+    return true;
 }
 
-void toggle_enable_media(EKeystate s)
+bool toggle_enable_media(EKeystate s)
 {
-    if (KEYSTATE_DOWN != s) return;
+    if (KEYSTATE_DOWN != s) return true;
     bool pause = LLViewerMedia::isAnyMediaPlaying() || LLViewerMedia::isAnyMediaShowing();
     LLViewerMedia::setAllMediaEnabled(!pause);
+    return true;
 }
 
-void walk_to(EKeystate s)
+bool walk_to(EKeystate s)
 {
-    LL_WARNS() << "processing " << LLSD(s).asString() << LL_ENDL;
-    if (KEYSTATE_DOWN != s) return;
-    LLToolPie::getInstance()->walkToClickedLocation();
+    if (KEYSTATE_DOWN != s) return true;
+    return LLToolPie::getInstance()->walkToClickedLocation();
+}
+
+bool teleport_to(EKeystate s)
+{
+    if (KEYSTATE_DOWN != s) return true;
+    return LLToolPie::getInstance()->teleportToClickedLocation();
+}
+
+bool toggle_voice(EKeystate s)
+{
+    if (KEYSTATE_DOWN != s) return true;
+    if (!LLAgent::isActionAllowed("speak")) return false;
+    LLVoiceClient::getInstance()->toggleUserPTTState();
+    return true;
+}
+
+bool voice_follow_key(EKeystate s)
+{
+    if (KEYSTATE_DOWN == s)
+    {
+        if (!LLAgent::isActionAllowed("speak")) return false;
+        LLVoiceClient::getInstance()->setUserPTTState(true);
+        return true;
+    }
+    else if (KEYSTATE_UP == s && LLVoiceClient::getInstance()->getUserPTTState())
+    {
+        LLVoiceClient::getInstance()->setUserPTTState(false);
+        return true;
+    }
+    return false;
 }
 
-void teleport_to(EKeystate s)
+bool agen_control_lbutton_handle(EKeystate s)
 {
-    if (KEYSTATE_DOWN != s) return;
-    LLToolPie::getInstance()->teleportToClickedLocation();
+    switch (s)
+    {
+    case KEYSTATE_DOWN:
+        gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN);
+        break;
+    case KEYSTATE_UP:
+        gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP);
+        break;
+    default:
+        break;
+    }
+    return true;
 }
 
 #define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, ACTION);
@@ -709,6 +796,8 @@ REGISTER_KEYBOARD_ACTION("toggle_pause_media", toggle_pause_media);
 REGISTER_KEYBOARD_ACTION("toggle_enable_media", toggle_enable_media);
 REGISTER_KEYBOARD_ACTION("teleport_to", teleport_to);
 REGISTER_KEYBOARD_ACTION("walk_to", walk_to);
+REGISTER_KEYBOARD_ACTION("toggle_voice", toggle_voice);
+REGISTER_KEYBOARD_ACTION("voice_follow_key", voice_follow_key);
 #undef REGISTER_KEYBOARD_ACTION
 
 LLViewerKeyboard::LLViewerKeyboard()
@@ -844,7 +933,7 @@ BOOL LLViewerKeyboard::handleKeyUp(KEY translated_key, MASK translated_mask)
 BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const bool ignore, const std::string& function_name)
 {
 	S32 index;
-	typedef boost::function<void(EKeystate)> function_t;
+	typedef boost::function<bool(EKeystate)> function_t;
 	function_t function = NULL;
 	std::string name;
 
@@ -935,7 +1024,7 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c
 BOOL LLViewerKeyboard::bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const bool ignore, const std::string& function_name)
 {
     S32 index;
-    typedef boost::function<void(EKeystate)> function_t;
+    typedef boost::function<bool(EKeystate)> function_t;
     function_t function = NULL;
 
     function_t* result = LLKeyboardActionRegistry::getValue(function_name);
@@ -1105,102 +1194,6 @@ S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode,
 	return binding_count;
 }
 
-S32 LLViewerKeyboard::loadBindings(const std::string& filename)
-{
-	LLFILE *fp;
-	const S32 BUFFER_SIZE = 2048;
-	char buffer[BUFFER_SIZE];	/* Flawfinder: ignore */
-	// *NOTE: This buffer size is hard coded into scanf() below.
-	char mode_string[MAX_STRING] = "";	/* Flawfinder: ignore */
-	char key_string[MAX_STRING] = "";	/* Flawfinder: ignore */
-	char mask_string[MAX_STRING] = "";	/* Flawfinder: ignore */
-	char function_string[MAX_STRING] = "";	/* Flawfinder: ignore */
-	S32 mode = MODE_THIRD_PERSON;
-	KEY key = 0;
-	MASK mask = 0;
-	S32 tokens_read;
-	S32 binding_count = 0;
-	S32 line_count = 0;
-
-	if(filename.empty())
-	{
-		LL_ERRS() << " No filename specified" << LL_ENDL;
-		return 0;
-	}
-
-	fp = LLFile::fopen(filename, "r");
-
-	if (!fp)
-	{
-		return 0;
-	}
-
-
-	while (!feof(fp))
-	{
-		line_count++;
-		if (!fgets(buffer, BUFFER_SIZE, fp))
-			break;
-
-		// skip over comments, blank lines
-		if (buffer[0] == '#' || buffer[0] == '\n') continue;
-
-		// grab the binding strings
-		tokens_read = sscanf(	/* Flawfinder: ignore */
-			buffer,
-			"%254s %254s %254s %254s",
-			mode_string,
-			key_string,
-			mask_string,
-			function_string);
-
-		if (tokens_read == EOF)
-		{
-			LL_INFOS() << "Unexpected end-of-file at line " << line_count << " of key binding file " << filename << LL_ENDL;
-			fclose(fp);
-			return 0;
-		}
-		else if (tokens_read < 4)
-		{
-			LL_INFOS() << "Can't read line " << line_count << " of key binding file " << filename << LL_ENDL;
-			continue;
-		}
-
-		// convert mode
-		if (!modeFromString(mode_string, &mode))
-		{
-			LL_INFOS() << "Unknown mode on line " << line_count << " of key binding file " << filename << LL_ENDL;
-			LL_INFOS() << "Mode must be one of FIRST_PERSON, THIRD_PERSON, EDIT, EDIT_AVATAR" << LL_ENDL;
-			continue;
-		}
-
-		// convert key
-		if (!LLKeyboard::keyFromString(key_string, &key))
-		{
-			LL_INFOS() << "Can't interpret key on line " << line_count << " of key binding file " << filename << LL_ENDL;
-			continue;
-		}
-
-		// convert mask
-		if (!LLKeyboard::maskFromString(mask_string, &mask))
-		{
-			LL_INFOS() << "Can't interpret mask on line " << line_count << " of key binding file " << filename << LL_ENDL;
-			continue;
-		}
-
-		// bind key
-		if (bindKey(mode, key, mask, false, function_string))
-		{
-			binding_count++;
-		}
-	}
-
-	fclose(fp);
-
-	return binding_count;
-}
-
-
 EKeyboardMode LLViewerKeyboard::getMode() const
 {
 	if ( gAgentCamera.cameraMouselook() )
@@ -1236,27 +1229,26 @@ bool LLViewerKeyboard::scanKey(const LLKeyboardBinding* binding,
 		{
 			if (binding[i].mMask == mask)
 			{
+				bool res = false;
 				if (key_down && !repeat)
 				{
 					// ...key went down this frame, call function
-					binding[i].mFunction( KEYSTATE_DOWN );
+					res = binding[i].mFunction( KEYSTATE_DOWN );
 					return true;
 				}
 				else if (key_up)
 				{
 					// ...key went down this frame, call function
-					binding[i].mFunction( KEYSTATE_UP );
-					return true;
+					res = binding[i].mFunction( KEYSTATE_UP );
 				}
 				else if (key_level)
 				{
 					// ...key held down from previous frame
 					// Not windows, just call the function.
-					binding[i].mFunction( KEYSTATE_LEVEL );
-					return true;
+					res = binding[i].mFunction( KEYSTATE_LEVEL );
 				}//if
 				// Key+Mask combinations are supposed to be unique, so we won't find anything else
-				return false;
+				return res;
 			}//if
 		}//if
 	}//for
@@ -1264,7 +1256,7 @@ bool LLViewerKeyboard::scanKey(const LLKeyboardBinding* binding,
 }
 
 // Called from scanKeyboard.
-void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) const
+bool LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) const
 {
 	if (LLApp::isExiting())
 	{
@@ -1277,17 +1269,31 @@ void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_lev
 
 	if (mKeyHandledByUI[key])
 	{
-		return;
+		return false;
 	}
 
 	// don't process key down on repeated keys
 	BOOL repeat = gKeyboard->getKeyRepeated(key);
 
-    if (scanKey(mKeyBindings[mode], mKeyBindingCount[mode], key, mask, key_down, key_up, key_level, repeat))
+    bool res = scanKey(mKeyBindings[mode], mKeyBindingCount[mode], key, mask, key_down, key_up, key_level, repeat);
+    if (!res)
     {
         // Nothing found, try ignore list
-        scanKey(mKeyIgnoreMask[mode], mKeyIgnoreMaskCount[mode], key, MASK_NONE, key_down, key_up, key_level, repeat);
+        res = scanKey(mKeyIgnoreMask[mode], mKeyIgnoreMaskCount[mode], key, MASK_NONE, key_down, key_up, key_level, repeat);
     }
+
+    if (!res && agent_control_lbutton.canHandle(CLICK_NONE, key, mask))
+    {
+        if (key_down && !repeat)
+        {
+            res = agen_control_lbutton_handle(KEYSTATE_DOWN);
+        }
+        if (key_up)
+        {
+            res = agen_control_lbutton_handle(KEYSTATE_UP);
+        }
+    }
+    return res;
 }
 
 BOOL LLViewerKeyboard::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down)
@@ -1368,23 +1374,30 @@ bool LLViewerKeyboard::scanMouse(const LLMouseBinding *binding, S32 binding_coun
     {
         if (binding[i].mMouse == mouse && binding[i].mMask == mask)
         {
+            bool res = false;
             switch (state)
             {
             case MOUSE_STATE_DOWN:
+                res = binding[i].mFunction(KEYSTATE_DOWN);
+                break;
             case MOUSE_STATE_CLICK:
-                binding[i].mFunction(KEYSTATE_DOWN);
+                // Button went down and up in scope of single frame
+                // might not work best with some functions,
+                // but some function need specific states specifically
+                res = binding[i].mFunction(KEYSTATE_DOWN);
+                res |= binding[i].mFunction(KEYSTATE_UP);
                 break;
             case MOUSE_STATE_LEVEL:
-                binding[i].mFunction(KEYSTATE_LEVEL);
+                res = binding[i].mFunction(KEYSTATE_LEVEL);
                 break;
             case MOUSE_STATE_UP:
-                binding[i].mFunction(KEYSTATE_UP);
+                res = binding[i].mFunction(KEYSTATE_UP);
                 break;
             default:
                 break;
             }
             // Key+Mask combinations are supposed to be unique, no need to continue
-            return true;
+            return res;
         }
     }
     return false;
@@ -1401,6 +1414,30 @@ bool LLViewerKeyboard::scanMouse(EMouseClickType click, EMouseState state) const
     {
         res = scanMouse(mMouseIgnoreMask[mode], mMouseIgnoreMaskCount[mode], click, MASK_NONE, state);
     }
+    // no user defined actions found or those actions can't handle the key/button, handle control if nessesary
+    if (!res && agent_control_lbutton.canHandle(click, KEY_NONE, mask))
+    {
+        switch (state)
+        {
+        case MOUSE_STATE_DOWN:
+            agen_control_lbutton_handle(KEYSTATE_DOWN);
+            res = true;
+            break;
+        case MOUSE_STATE_CLICK:
+            // might not work best with some functions,
+            // but some function need specific states too specifically
+            agen_control_lbutton_handle(KEYSTATE_DOWN);
+            agen_control_lbutton_handle(KEYSTATE_UP);
+            res = true;
+            break;
+        case MOUSE_STATE_UP:
+            agen_control_lbutton_handle(KEYSTATE_UP);
+            res = true;
+            break;
+        default:
+            break;
+        }
+    }
     return res;
 }
 
@@ -1413,7 +1450,7 @@ void LLViewerKeyboard::scanMouse()
             scanMouse((EMouseClickType)i, mMouseLevel[i]);
             if (mMouseLevel[i] == MOUSE_STATE_DOWN)
             {
-                // mouse doesn't support 'continued' state like keyboard does, so after handling, switch to LEVEL
+                // mouse doesn't support 'continued' state, so after handling, switch to LEVEL
                 mMouseLevel[i] = MOUSE_STATE_LEVEL;
             }
             else if (mMouseLevel[i] == MOUSE_STATE_UP || mMouseLevel[i] == MOUSE_STATE_CLICK)
diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h
index 10b16e5fa0..02fa21d4f2 100644
--- a/indra/newview/llviewerkeyboard.h
+++ b/indra/newview/llviewerkeyboard.h
@@ -115,14 +115,16 @@ public:
 	BOOL			handleKey(KEY key, MASK mask, BOOL repeated);
 	BOOL			handleKeyUp(KEY key, MASK mask);
 
-	S32				loadBindings(const std::string& filename);										// returns number bound, 0 on error
 	S32				loadBindingsXML(const std::string& filename);										// returns number bound, 0 on error
 	EKeyboardMode	getMode() const;
 
 	BOOL			modeFromString(const std::string& string, S32 *mode) const;			// False on failure
 	BOOL			mouseFromString(const std::string& string, EMouseClickType *mode) const;// False on failure
 
-    void			scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) const;
+    bool            scanKey(KEY key,
+                            BOOL key_down,
+                            BOOL key_up,
+                            BOOL key_level) const;
 
     // handleMouse() records state, scanMouse() goes through states, scanMouse(click) processes individual saved states after UI is done with them
     BOOL			handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down);
@@ -163,6 +165,10 @@ private:
     // This way with W+ignore defined to 'forward' and with ctrl+W tied to camera,
     // pressing undefined Shift+W will do 'forward', yet ctrl+W will do 'camera forward'
     // With A defined to 'turn', shift+A defined to strafe, pressing Shift+W+A will do strafe+forward
+
+    // TODO: at some point it is better to remake this, especially keyaboard part
+    // would be much better to send to functions actual state of the button than
+    // to send what we think function wants based on collection of bools (mKeyRepeated, mKeyLevel, mKeyDown)
     S32				mKeyBindingCount[MODE_COUNT];
     S32				mKeyIgnoreMaskCount[MODE_COUNT];
     S32				mMouseBindingCount[MODE_COUNT];
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index bd5370f07f..caf7a8a65a 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -918,8 +918,6 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK m
 	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))
 	{	
@@ -1437,9 +1435,6 @@ void LLViewerWindow::handleFocusLost(LLWindow *window)
 
 BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key,  MASK mask, BOOL repeated)
 {
-	// Let the voice chat code check for its PTT key.  Note that this never affects event processing.
-	LLVoiceClient::getInstance()->keyDown(key, mask);
-
 	if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME)
 	{
 		gAgent.clearAFK();
@@ -1464,9 +1459,6 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key,  MASK mask, BOOL repeated)
 
 BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key,  MASK mask)
 {
-	// Let the voice chat code check for its PTT key.  Note that this never affects event processing.
-	LLVoiceClient::getInstance()->keyUp(key, mask);
-
 	// Let the inspect tool code check for ALT key to set LLToolSelectRect active instead LLToolCamera
 	LLToolCompInspect * tool_inspectp = LLToolCompInspect::getInstance();
 	if (LLToolMgr::getInstance()->getCurrentTool() == tool_inspectp)
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index fcca081647..041f617ae5 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -199,8 +199,6 @@ const LLVoiceVersionInfo LLVoiceClient::getVersion()
 void LLVoiceClient::updateSettings()
 {
 	setUsePTT(gSavedSettings.getBOOL("PTTCurrentlyEnabled"));
-	std::string keyString = gSavedSettings.getString("PushToTalkButton");
-	setPTTKey(keyString);
 	setPTTIsToggle(gSavedSettings.getBOOL("PushToTalkToggle"));
 	mDisableMic = gSavedSettings.getBOOL("VoiceDisableMic");
 
@@ -636,32 +634,6 @@ bool LLVoiceClient::getPTTIsToggle()
 	return mPTTIsToggle;
 }
 
-void LLVoiceClient::setPTTKey(std::string &key)
-{
-	// Value is stored as text for readability
-	if(key == "MiddleMouse")
-	{
-		mPTTMouseButton = CLICK_MIDDLE;
-	}
-	else if(key == "MouseButton4")
-	{
-		mPTTMouseButton = CLICK_BUTTON4;
-	}
-	else if (key == "MouseButton5")
-	{
-		mPTTMouseButton = CLICK_BUTTON5;
-	}
-	else
-	{
-		mPTTMouseButton = 0;
-		if(!LLKeyboard::keyFromString(key, &mPTTKey))
-		{
-			// If the call failed, don't match any key.
-			key = KEY_NONE;
-		}
-	}
-}
-
 void LLVoiceClient::inputUserControlState(bool down)
 {
 	if(mPTTIsToggle)
@@ -682,48 +654,6 @@ void LLVoiceClient::toggleUserPTTState(void)
 	setUserPTTState(!getUserPTTState());
 }
 
-void LLVoiceClient::keyDown(KEY key, MASK mask)
-{	
-	if (gKeyboard->getKeyRepeated(key))
-	{
-		// ignore auto-repeat keys                                                                         
-		return;
-	}
-	
-    //
-	/*static LLCachedControl<LLSD> 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)
-{
-	/*static LLCachedControl<LLKeyBind> 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)
-{
-	/*static LLCachedControl<LLKeyBind> mouse_bind(gSavedSettings, "control_toggle_voice");
-	if (mouse_bind().canHandleMouse((EMouseClickType)click, mask))
-	{
-		inputUserControlState(down);
-	}*/
-}
-
 
 //-------------------------------------------
 // nearby speaker accessors
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index e3285b0c9b..52f4ff13b5 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -409,16 +409,10 @@ public:
 	void setUsePTT(bool usePTT);
 	void setPTTIsToggle(bool PTTIsToggle);
 	bool getPTTIsToggle();	
-	void setPTTKey(std::string &key);
-	
+
 	void updateMicMuteLogic();
-	
+
 	BOOL lipSyncEnabled();
-	
-	// PTT key triggering
-	void keyDown(KEY key, MASK mask);
-	void keyUp(KEY key, MASK mask);
-	void updateMouseState(S32 click, MASK mask, bool down);
 
 	boost::signals2::connection MicroChangedCallback(const micro_changed_signal_t::slot_type& cb ) { return mMicroChangedSignal.connect(cb); }
 
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
index 0c652845f0..ac4be34be2 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
@@ -274,10 +274,6 @@
      label="Sitting"
      name="sitting"
      value="4"/>
-    <combo_box.item
-     label="General"
-     name="general"
-     value="5"/>
   </combo_box>
 
   <button
@@ -301,6 +297,7 @@
    right="-3"
    can_sort="false"
    multi_select="false"
+   bg_selected_color="Transparent"
    name="controls_list">
     <scroll_list.columns
      relative_width="0.34"
-- 
cgit v1.2.3


From f71cce50f26c197c1b2ce510b7a646d22a2eab26 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Fri, 27 Sep 2019 15:25:47 +0300
Subject: SL-6109 Small reorganisation

---
 indra/newview/CMakeLists.txt                       |    4 +-
 indra/newview/llappviewer.cpp                      |    8 +-
 indra/newview/llkeyconflict.cpp                    |   20 +-
 indra/newview/llkeyconflict.h                      |    4 +-
 indra/newview/llviewerinput.cpp                    | 1461 +++++++++++++++++++
 indra/newview/llviewerinput.h                      |  193 +++
 indra/newview/llviewerkeyboard.cpp                 | 1462 --------------------
 indra/newview/llviewerkeyboard.h                   |  193 ---
 indra/newview/llviewerwindow.cpp                   |   30 +-
 indra/newview/llwindowlistener.cpp                 |    6 +-
 .../default/xui/en/panel_preferences_controls.xml  |    5 +-
 11 files changed, 1691 insertions(+), 1695 deletions(-)
 create mode 100644 indra/newview/llviewerinput.cpp
 create mode 100644 indra/newview/llviewerinput.h
 delete mode 100644 indra/newview/llviewerkeyboard.cpp
 delete mode 100644 indra/newview/llviewerkeyboard.h

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index bfbe1a0cfd..9a72fcc228 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -653,7 +653,7 @@ set(viewer_SOURCE_FILES
     llviewerjointattachment.cpp
     llviewerjointmesh.cpp
     llviewerjoystick.cpp
-    llviewerkeyboard.cpp
+    llviewerinput.cpp
     llviewerlayer.cpp
     llviewermedia.cpp
     llviewermedia_streamingaudio.cpp
@@ -1275,7 +1275,7 @@ set(viewer_HEADER_FILES
     llviewerjointattachment.h
     llviewerjointmesh.h
     llviewerjoystick.h
-    llviewerkeyboard.h
+    llviewerinput.h
     llviewerlayer.h
     llviewermedia.h
     llviewermediafocus.h
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 97e770a106..1023a553f8 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -149,7 +149,7 @@
 #include "llapr.h"
 #include <boost/lexical_cast.hpp>
 
-#include "llviewerkeyboard.h"
+#include "llviewerinput.h"
 #include "lllfsthread.h"
 #include "llworkerthread.h"
 #include "lltexturecache.h"
@@ -1006,11 +1006,11 @@ bool LLAppViewer::init()
 
 	// Load User's bindings
 	std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "keys.xml");
-	if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerKeyboard.loadBindingsXML(key_bindings_file))
+	if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file))
 	{
 		// Failed to load custom bindings, try default ones
 		key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "keys.xml");
-		if (!gViewerKeyboard.loadBindingsXML(key_bindings_file))
+		if (!gViewerInput.loadBindingsXML(key_bindings_file))
 		{
 			LL_ERRS("InitInfo") << "Unable to open default key bindings from" << key_bindings_file << LL_ENDL;
 		}
@@ -1446,7 +1446,7 @@ bool LLAppViewer::doFrame()
 			{
 				joystick->scanJoystick();
 				gKeyboard->scanKeyboard();
-                gViewerKeyboard.scanMouse();
+                gViewerInput.scanMouse();
 			}
 
 			// Update state based on messages, user input, object idle.
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index 66d420369e..e81d121e3b 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -37,7 +37,7 @@
 #include "llinitparam.h"
 #include "llkeyboard.h"
 #include "llviewercontrol.h"
-#include "llviewerkeyboard.h"
+#include "llviewerinput.h"
 #include "llxuiparser.h"
 //#include "llstring.h"
 
@@ -117,7 +117,7 @@ static const std::string typetostring[LLKeyConflictHandler::CONTROL_NUM_INDICES]
     "control_cntrl_select"
 };
 
-// note, a solution is needed that will keep this up to date with llviewerkeyboard
+// note, a solution is needed that will keep this up to date with llviewerinput
 typedef std::map<std::string, LLKeyConflictHandler::EControlTypes> control_enum_t;
 static const control_enum_t command_to_key =
 {
@@ -358,9 +358,9 @@ std::string LLKeyConflictHandler::getControlString(EControlTypes control_type, U
     return getStringFromKeyData(mControlsMap[control_type].getKeyData(index));
 }
 
-void  LLKeyConflictHandler::loadFromSettings(const LLViewerKeyboard::KeyMode& keymode, control_map_t *destination)
+void  LLKeyConflictHandler::loadFromSettings(const LLViewerInput::KeyMode& keymode, control_map_t *destination)
 {
-    for (LLInitParam::ParamIterator<LLViewerKeyboard::KeyBinding>::const_iterator it = keymode.bindings.begin(),
+    for (LLInitParam::ParamIterator<LLViewerInput::KeyBinding>::const_iterator it = keymode.bindings.begin(),
         end_it = keymode.bindings.end();
         it != end_it;
     ++it)
@@ -400,7 +400,7 @@ void LLKeyConflictHandler::loadFromSettings(const ESourceMode &load_mode, const
         return;
     }
 
-    LLViewerKeyboard::Keys keys;
+    LLViewerInput::Keys keys;
     LLSimpleXUIParser parser;
 
     if (parser.readXUI(filename, keys)
@@ -556,7 +556,7 @@ void  LLKeyConflictHandler::saveToSettings()
             gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
             gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
 
-        LLViewerKeyboard::Keys keys;
+        LLViewerInput::Keys keys;
         LLSimpleXUIParser parser;
 
         if (parser.readXUI(filename, keys)
@@ -566,8 +566,8 @@ void  LLKeyConflictHandler::saveToSettings()
 
             // todo: fix this
             // workaround to avoid doing own param container 
-            LLViewerKeyboard::KeyMode mode;
-            LLViewerKeyboard::KeyBinding binding;
+            LLViewerInput::KeyMode mode;
+            LLViewerInput::KeyBinding binding;
 
             control_map_t::iterator iter = mControlsMap.begin();
             control_map_t::iterator end = mControlsMap.end();
@@ -657,7 +657,7 @@ void  LLKeyConflictHandler::saveToSettings()
             // Now force a rebind for keyboard
             if (gDirUtilp->fileExists(filename))
             {
-                gViewerKeyboard.loadBindingsXML(filename);
+                gViewerInput.loadBindingsXML(filename);
             }
         }
     }
@@ -816,7 +816,7 @@ void LLKeyConflictHandler::resetKeyboardBindings()
         gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
         gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
     
-    gViewerKeyboard.loadBindingsXML(filename);
+    gViewerInput.loadBindingsXML(filename);
 }
 
 void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode)
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index 00fbe18863..e4a6da30d0 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -28,7 +28,7 @@
 #define LL_LLKEYCONFLICT_H
 
 #include "llkeybind.h"
-#include "llviewerkeyboard.h"
+#include "llviewerinput.h"
 
 
 class LLKeyConflict
@@ -195,7 +195,7 @@ private:
     void registerTemporaryControl(EControlTypes control_type, EMouseClickType mouse_ind, KEY key, MASK mask, U32 conflict_mask);
 
     typedef std::map<EControlTypes, LLKeyConflict> control_map_t;
-    void loadFromSettings(const LLViewerKeyboard::KeyMode& keymode, control_map_t *destination);
+    void loadFromSettings(const LLViewerInput::KeyMode& keymode, control_map_t *destination);
     void loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination);
     void resetKeyboardBindings();
     void generatePlaceholders(ESourceMode load_mode); //E.x. non-assignable values
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
new file mode 100644
index 0000000000..11f430cda3
--- /dev/null
+++ b/indra/newview/llviewerinput.cpp
@@ -0,0 +1,1461 @@
+/** 
+ * @file llviewerinput.cpp
+ * @brief LLViewerInput class implementation
+ *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llviewerinput.h"
+
+#include "llappviewer.h"
+#include "llfloaterreg.h"
+#include "llmath.h"
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llfloaterimnearbychat.h"
+#include "llfocusmgr.h"
+#include "llkeybind.h" // LLKeyData
+#include "llmorphview.h"
+#include "llmoveview.h"
+#include "lltoolfocus.h"
+#include "lltoolpie.h"
+#include "llviewercontrol.h"
+#include "llviewerwindow.h"
+#include "llvoavatarself.h"
+#include "llfloatercamera.h"
+#include "llinitparam.h"
+
+//
+// Constants
+//
+
+const F32 FLY_TIME = 0.5f;
+const F32 FLY_FRAMES = 4;
+
+const F32 NUDGE_TIME = 0.25f;  // in seconds
+const S32 NUDGE_FRAMES = 2;
+const F32 ORBIT_NUDGE_RATE = 0.05f;  // fraction of normal speed
+
+const LLKeyData agent_control_lbutton(CLICK_LEFT, KEY_NONE, MASK_NONE, true);
+
+struct LLKeyboardActionRegistry 
+:	public LLRegistrySingleton<std::string, boost::function<bool (EKeystate keystate)>, LLKeyboardActionRegistry>
+{
+	LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry);
+};
+
+LLViewerInput gViewerInput;
+
+bool agent_jump( EKeystate s )
+{
+	static BOOL first_fly_attempt(TRUE);
+	if (KEYSTATE_UP == s)
+	{
+		first_fly_attempt = TRUE;
+		return true;
+	}
+	F32 time = gKeyboard->getCurKeyElapsedTime();
+	S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
+
+	if( time < FLY_TIME 
+		|| frame_count <= FLY_FRAMES 
+		|| gAgent.upGrabbed()
+		|| !gSavedSettings.getBOOL("AutomaticFly"))
+	{
+		gAgent.moveUp(1);
+	}
+	else
+	{
+		gAgent.setFlying(TRUE, first_fly_attempt);
+		first_fly_attempt = FALSE;
+		gAgent.moveUp(1);
+	}
+	return true;
+}
+
+bool agent_push_down( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gAgent.moveUp(-1);
+	return true;
+}
+
+static void agent_check_temporary_run(LLAgent::EDoubleTapRunMode mode)
+{
+	if (gAgent.mDoubleTapRunMode == mode &&
+		gAgent.getRunning() &&
+		!gAgent.getAlwaysRun())
+	{
+		// Turn off temporary running.
+		gAgent.clearRunning();
+		gAgent.sendWalkRun(gAgent.getRunning());
+	}
+}
+
+static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode mode)
+{
+	if (KEYSTATE_UP == s)
+	{
+		// Note: in case shift is already released, slide left/right run
+		// will be released in agent_turn_left()/agent_turn_right()
+		agent_check_temporary_run(mode);
+	}
+	else if (gSavedSettings.getBOOL("AllowTapTapHoldRun") &&
+		 KEYSTATE_DOWN == s &&
+		 !gAgent.getRunning())
+	{
+		if (gAgent.mDoubleTapRunMode == mode &&
+		    gAgent.mDoubleTapRunTimer.getElapsedTimeF32() < NUDGE_TIME)
+		{
+			// Same walk-key was pushed again quickly; this is a
+			// double-tap so engage temporary running.
+			gAgent.setRunning();
+			gAgent.sendWalkRun(gAgent.getRunning());
+		}
+
+		// Pressing any walk-key resets the double-tap timer
+		gAgent.mDoubleTapRunTimer.reset();
+		gAgent.mDoubleTapRunMode = mode;
+	}
+}
+
+static void agent_push_forwardbackward( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode )
+{
+	agent_handle_doubletap_run(s, mode);
+	if (KEYSTATE_UP == s) return;
+
+	F32 time = gKeyboard->getCurKeyElapsedTime();
+	S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
+
+	if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES)
+	{
+		gAgent.moveAtNudge(direction);
+	}
+	else
+	{
+		gAgent.moveAt(direction);
+	}
+}
+
+bool camera_move_forward( EKeystate s );
+
+bool agent_push_forward( EKeystate s )
+{
+	if(gAgent.isMovementLocked()) return true;
+
+	//in free camera control mode we need to intercept keyboard events for avatar movements
+	if (LLFloaterCamera::inFreeCameraMode())
+	{
+		camera_move_forward(s);
+	}
+	else
+	{
+		agent_push_forwardbackward(s, 1, LLAgent::DOUBLETAP_FORWARD);
+	}
+	return true;
+}
+
+bool camera_move_backward( EKeystate s );
+
+bool agent_push_backward( EKeystate s )
+{
+	if(gAgent.isMovementLocked()) return true;
+
+	//in free camera control mode we need to intercept keyboard events for avatar movements
+	if (LLFloaterCamera::inFreeCameraMode())
+	{
+		camera_move_backward(s);
+	}
+	else if (!gAgent.backwardGrabbed() && gAgentAvatarp->isSitting() && gSavedSettings.getBOOL("LeaveMouselook"))
+	{
+		gAgentCamera.changeCameraToThirdPerson();
+	}
+	else
+	{
+		agent_push_forwardbackward(s, -1, LLAgent::DOUBLETAP_BACKWARD);
+	}
+	return true;
+}
+
+static void agent_slide_leftright( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode )
+{
+	agent_handle_doubletap_run(s, mode);
+	if( KEYSTATE_UP == s ) return;
+	F32 time = gKeyboard->getCurKeyElapsedTime();
+	S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
+
+	if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES)
+	{
+		gAgent.moveLeftNudge(direction);
+	}
+	else
+	{
+		gAgent.moveLeft(direction);
+	}
+}
+
+
+bool agent_slide_left( EKeystate s )
+{
+	if(gAgent.isMovementLocked()) return true;
+	agent_slide_leftright(s, 1, LLAgent::DOUBLETAP_SLIDELEFT);
+	return true;
+}
+
+
+bool agent_slide_right( EKeystate s )
+{
+	if(gAgent.isMovementLocked()) return true;
+	agent_slide_leftright(s, -1, LLAgent::DOUBLETAP_SLIDERIGHT);
+	return true;
+}
+
+bool camera_spin_around_cw( EKeystate s );
+
+bool agent_turn_left(EKeystate s)
+{
+	//in free camera control mode we need to intercept keyboard events for avatar movements
+	if (LLFloaterCamera::inFreeCameraMode())
+	{
+		camera_spin_around_cw(s);
+		return true;
+	}
+
+	if(gAgent.isMovementLocked()) return false;
+
+	if (LLToolCamera::getInstance()->mouseSteerMode())
+	{
+		agent_slide_left(s);
+	}
+	else
+	{
+		if (KEYSTATE_UP == s)
+		{
+			// Check temporary running. In case user released 'left' key with shift already released.
+			agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDELEFT);
+			return true;
+		}
+		F32 time = gKeyboard->getCurKeyElapsedTime();
+		gAgent.moveYaw( LLFloaterMove::getYawRate( time ) );
+	}
+	return true;
+}
+
+bool camera_spin_around_ccw( EKeystate s );
+
+bool agent_turn_right( EKeystate s )
+{
+	//in free camera control mode we need to intercept keyboard events for avatar movements
+	if (LLFloaterCamera::inFreeCameraMode())
+	{
+		camera_spin_around_ccw(s);
+		return true;
+	}
+
+	if(gAgent.isMovementLocked()) return false;
+
+	if (LLToolCamera::getInstance()->mouseSteerMode())
+	{
+		agent_slide_right(s);
+	}
+	else
+	{
+		if (KEYSTATE_UP == s)
+		{
+			// Check temporary running. In case user released 'right' key with shift already released.
+			agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDERIGHT);
+			return true;
+		}
+		F32 time = gKeyboard->getCurKeyElapsedTime();
+		gAgent.moveYaw( -LLFloaterMove::getYawRate( time ) );
+	}
+	return true;
+}
+
+bool agent_look_up( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gAgent.movePitch(-1);
+	//gAgent.rotate(-2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
+	return true;
+}
+
+
+bool agent_look_down( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gAgent.movePitch(1);
+	//gAgent.rotate(2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
+	return true;
+}
+
+bool agent_toggle_fly( EKeystate s )
+{
+	// Only catch the edge
+	if (KEYSTATE_DOWN == s )
+	{
+		LLAgent::toggleFlying();
+	}
+	return true;
+}
+
+F32 get_orbit_rate()
+{
+	F32 time = gKeyboard->getCurKeyElapsedTime();
+	if( time < NUDGE_TIME )
+	{
+		F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME;
+		//LL_INFOS() << rate << LL_ENDL;
+		return rate;
+	}
+	else
+	{
+		return 1;
+	}
+}
+
+bool camera_spin_around_ccw( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gAgentCamera.unlockView();
+	gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
+	return true;
+}
+
+
+bool camera_spin_around_cw( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gAgentCamera.unlockView();
+	gAgentCamera.setOrbitRightKey( get_orbit_rate() );
+	return true;
+}
+
+bool camera_spin_around_ccw_sitting( EKeystate s )
+{
+	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT ) return true;
+	if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning())
+	{
+		//send keystrokes, but do not change camera
+		agent_turn_right(s);
+	}
+	else
+	{
+		//change camera but do not send keystrokes
+		gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
+	}
+	return true;
+}
+
+
+bool camera_spin_around_cw_sitting( EKeystate s )
+{
+	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT ) return true;
+	if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning())
+	{
+		//send keystrokes, but do not change camera
+		agent_turn_left(s);
+	}
+	else
+	{
+		//change camera but do not send keystrokes
+		gAgentCamera.setOrbitRightKey( get_orbit_rate() );
+	}
+	return true;
+}
+
+
+bool camera_spin_over( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gAgentCamera.unlockView();
+	gAgentCamera.setOrbitUpKey( get_orbit_rate() );
+	return true;
+}
+
+
+bool camera_spin_under( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gAgentCamera.unlockView();
+	gAgentCamera.setOrbitDownKey( get_orbit_rate() );
+	return true;
+}
+
+bool camera_spin_over_sitting( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	if (gAgent.upGrabbed() || gAgentCamera.sitCameraEnabled())
+	{
+		//send keystrokes, but do not change camera
+		agent_jump(s);
+	}
+	else
+	{
+		//change camera but do not send keystrokes
+		gAgentCamera.setOrbitUpKey( get_orbit_rate() );
+	}
+	return true;
+}
+
+
+bool camera_spin_under_sitting( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	if (gAgent.downGrabbed() || gAgentCamera.sitCameraEnabled())
+	{
+		//send keystrokes, but do not change camera
+		agent_push_down(s);
+	}
+	else
+	{
+		//change camera but do not send keystrokes
+		gAgentCamera.setOrbitDownKey( get_orbit_rate() );
+	}
+	return true;
+}
+
+bool camera_move_forward( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gAgentCamera.unlockView();
+	gAgentCamera.setOrbitInKey( get_orbit_rate() );
+	return true;
+}
+
+
+bool camera_move_backward( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gAgentCamera.unlockView();
+	gAgentCamera.setOrbitOutKey( get_orbit_rate() );
+	return true;
+}
+
+bool camera_move_forward_sitting( EKeystate s )
+{
+	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD ) return true;
+	if (gAgent.forwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun()))
+	{
+		agent_push_forward(s);
+	}
+	else
+	{
+		gAgentCamera.setOrbitInKey( get_orbit_rate() );
+	}
+	return true;
+}
+
+bool camera_move_backward_sitting( EKeystate s )
+{
+	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD ) return true;
+
+	if (gAgent.backwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun()))
+	{
+		agent_push_backward(s);
+	}
+	else
+	{
+		gAgentCamera.setOrbitOutKey( get_orbit_rate() );
+	}
+	return true;
+}
+
+bool camera_pan_up( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gAgentCamera.unlockView();
+	gAgentCamera.setPanUpKey( get_orbit_rate() );
+	return true;
+}
+
+bool camera_pan_down( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gAgentCamera.unlockView();
+	gAgentCamera.setPanDownKey( get_orbit_rate() );
+	return true;
+}
+
+bool camera_pan_left( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gAgentCamera.unlockView();
+	gAgentCamera.setPanLeftKey( get_orbit_rate() );
+	return true;
+}
+
+bool camera_pan_right( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gAgentCamera.unlockView();
+	gAgentCamera.setPanRightKey( get_orbit_rate() );
+	return true;
+}
+
+bool camera_pan_in( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gAgentCamera.unlockView();
+	gAgentCamera.setPanInKey( get_orbit_rate() );
+	return true;
+}
+
+bool camera_pan_out( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gAgentCamera.unlockView();
+	gAgentCamera.setPanOutKey( get_orbit_rate() );
+	return true;
+}
+
+bool camera_move_forward_fast( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gAgentCamera.unlockView();
+	gAgentCamera.setOrbitInKey(2.5f);
+	return true;
+}
+
+bool camera_move_backward_fast( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gAgentCamera.unlockView();
+	gAgentCamera.setOrbitOutKey(2.5f);
+	return true;
+}
+
+
+bool edit_avatar_spin_ccw( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gMorphView->setCameraDrivenByKeys( TRUE );
+	gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
+	//gMorphView->orbitLeft( get_orbit_rate() );
+	return true;
+}
+
+
+bool edit_avatar_spin_cw( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gMorphView->setCameraDrivenByKeys( TRUE );
+	gAgentCamera.setOrbitRightKey( get_orbit_rate() );
+	//gMorphView->orbitRight( get_orbit_rate() );
+	return true;
+}
+
+bool edit_avatar_spin_over( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gMorphView->setCameraDrivenByKeys( TRUE );
+	gAgentCamera.setOrbitUpKey( get_orbit_rate() );
+	//gMorphView->orbitUp( get_orbit_rate() );
+	return true;
+}
+
+
+bool edit_avatar_spin_under( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gMorphView->setCameraDrivenByKeys( TRUE );
+	gAgentCamera.setOrbitDownKey( get_orbit_rate() );
+	//gMorphView->orbitDown( get_orbit_rate() );
+	return true;
+}
+
+bool edit_avatar_move_forward( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gMorphView->setCameraDrivenByKeys( TRUE );
+	gAgentCamera.setOrbitInKey( get_orbit_rate() );
+	//gMorphView->orbitIn();
+	return true;
+}
+
+
+bool edit_avatar_move_backward( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return true;
+	gMorphView->setCameraDrivenByKeys( TRUE );
+	gAgentCamera.setOrbitOutKey( get_orbit_rate() );
+	//gMorphView->orbitOut();
+	return true;
+}
+
+bool stop_moving( EKeystate s )
+{
+	if( KEYSTATE_DOWN != s  ) return true;
+	// stop agent
+	gAgent.setControlFlags(AGENT_CONTROL_STOP);
+
+	// cancel autopilot
+	gAgent.stopAutoPilot();
+	return true;
+}
+
+bool start_chat( EKeystate s )
+{
+    if (LLAppViewer::instance()->quitRequested())
+    {
+        return true; // can't talk, gotta go, kthxbye!
+    }
+    if (KEYSTATE_DOWN != s) return true;
+
+	// start chat
+	LLFloaterIMNearbyChat::startChat(NULL);
+	return true;
+}
+
+bool start_gesture( EKeystate s )
+{
+	LLUICtrl* focus_ctrlp = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
+	if (KEYSTATE_UP == s &&
+		! (focus_ctrlp && focus_ctrlp->acceptsTextInput()))
+	{
+ 		if ((LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"))->getCurrentChat().empty())
+ 		{
+ 			// No existing chat in chat editor, insert '/'
+ 			LLFloaterIMNearbyChat::startChat("/");
+ 		}
+ 		else
+ 		{
+ 			// Don't overwrite existing text in chat editor
+ 			LLFloaterIMNearbyChat::startChat(NULL);
+ 		}
+	}
+	return true;
+}
+
+bool toggle_run(EKeystate s)
+{
+    if (KEYSTATE_DOWN != s) return true;
+    bool run = gAgent.getAlwaysRun();
+    if (run)
+    {
+        gAgent.clearAlwaysRun();
+        gAgent.clearRunning();
+    }
+    else
+    {
+        gAgent.setAlwaysRun();
+        gAgent.setRunning();
+    }
+    gAgent.sendWalkRun(!run);
+	return true;
+}
+
+bool toggle_sit(EKeystate s)
+{
+    if (KEYSTATE_DOWN != s) return true;
+    if (gAgent.isSitting())
+    {
+        gAgent.standUp();
+    }
+    else
+    {
+        gAgent.sitDown();
+    }
+	return true;
+}
+
+bool toggle_pause_media(EKeystate s) // analogue of play/pause button in top bar
+{
+    if (KEYSTATE_DOWN != s) return true;
+    bool pause = LLViewerMedia::isAnyMediaPlaying();
+    LLViewerMedia::setAllMediaPaused(pause);
+    return true;
+}
+
+bool toggle_enable_media(EKeystate s)
+{
+    if (KEYSTATE_DOWN != s) return true;
+    bool pause = LLViewerMedia::isAnyMediaPlaying() || LLViewerMedia::isAnyMediaShowing();
+    LLViewerMedia::setAllMediaEnabled(!pause);
+    return true;
+}
+
+bool walk_to(EKeystate s)
+{
+    if (KEYSTATE_DOWN != s) return true;
+    return LLToolPie::getInstance()->walkToClickedLocation();
+}
+
+bool teleport_to(EKeystate s)
+{
+    if (KEYSTATE_DOWN != s) return true;
+    return LLToolPie::getInstance()->teleportToClickedLocation();
+}
+
+bool toggle_voice(EKeystate s)
+{
+    if (KEYSTATE_DOWN != s) return true;
+    if (!LLAgent::isActionAllowed("speak")) return false;
+    LLVoiceClient::getInstance()->toggleUserPTTState();
+    return true;
+}
+
+bool voice_follow_key(EKeystate s)
+{
+    if (KEYSTATE_DOWN == s)
+    {
+        if (!LLAgent::isActionAllowed("speak")) return false;
+        LLVoiceClient::getInstance()->setUserPTTState(true);
+        return true;
+    }
+    else if (KEYSTATE_UP == s && LLVoiceClient::getInstance()->getUserPTTState())
+    {
+        LLVoiceClient::getInstance()->setUserPTTState(false);
+        return true;
+    }
+    return false;
+}
+
+bool agen_control_lbutton_handle(EKeystate s)
+{
+    switch (s)
+    {
+    case KEYSTATE_DOWN:
+        gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN);
+        break;
+    case KEYSTATE_UP:
+        gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP);
+        break;
+    default:
+        break;
+    }
+    return true;
+}
+
+#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);
+REGISTER_KEYBOARD_ACTION("push_forward", agent_push_forward);
+REGISTER_KEYBOARD_ACTION("push_backward", agent_push_backward);
+REGISTER_KEYBOARD_ACTION("look_up", agent_look_up);
+REGISTER_KEYBOARD_ACTION("look_down", agent_look_down);
+REGISTER_KEYBOARD_ACTION("toggle_fly", agent_toggle_fly);
+REGISTER_KEYBOARD_ACTION("turn_left", agent_turn_left);
+REGISTER_KEYBOARD_ACTION("turn_right", agent_turn_right);
+REGISTER_KEYBOARD_ACTION("slide_left", agent_slide_left);
+REGISTER_KEYBOARD_ACTION("slide_right", agent_slide_right);
+REGISTER_KEYBOARD_ACTION("spin_around_ccw", camera_spin_around_ccw);
+REGISTER_KEYBOARD_ACTION("spin_around_cw", camera_spin_around_cw);
+REGISTER_KEYBOARD_ACTION("spin_around_ccw_sitting", camera_spin_around_ccw_sitting);
+REGISTER_KEYBOARD_ACTION("spin_around_cw_sitting", camera_spin_around_cw_sitting);
+REGISTER_KEYBOARD_ACTION("spin_over", camera_spin_over);
+REGISTER_KEYBOARD_ACTION("spin_under", camera_spin_under);
+REGISTER_KEYBOARD_ACTION("spin_over_sitting", camera_spin_over_sitting);
+REGISTER_KEYBOARD_ACTION("spin_under_sitting", camera_spin_under_sitting);
+REGISTER_KEYBOARD_ACTION("move_forward", camera_move_forward);
+REGISTER_KEYBOARD_ACTION("move_backward", camera_move_backward);
+REGISTER_KEYBOARD_ACTION("move_forward_sitting", camera_move_forward_sitting);
+REGISTER_KEYBOARD_ACTION("move_backward_sitting", camera_move_backward_sitting);
+REGISTER_KEYBOARD_ACTION("pan_up", camera_pan_up);
+REGISTER_KEYBOARD_ACTION("pan_down", camera_pan_down);
+REGISTER_KEYBOARD_ACTION("pan_left", camera_pan_left);
+REGISTER_KEYBOARD_ACTION("pan_right", camera_pan_right);
+REGISTER_KEYBOARD_ACTION("pan_in", camera_pan_in);
+REGISTER_KEYBOARD_ACTION("pan_out", camera_pan_out);
+REGISTER_KEYBOARD_ACTION("move_forward_fast", camera_move_forward_fast);
+REGISTER_KEYBOARD_ACTION("move_backward_fast", camera_move_backward_fast);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_ccw", edit_avatar_spin_ccw);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_cw", edit_avatar_spin_cw);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_over", edit_avatar_spin_over);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_under", edit_avatar_spin_under);
+REGISTER_KEYBOARD_ACTION("edit_avatar_move_forward", edit_avatar_move_forward);
+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_run", toggle_run);
+REGISTER_KEYBOARD_ACTION("toggle_sit", toggle_sit);
+REGISTER_KEYBOARD_ACTION("toggle_pause_media", toggle_pause_media);
+REGISTER_KEYBOARD_ACTION("toggle_enable_media", toggle_enable_media);
+REGISTER_KEYBOARD_ACTION("teleport_to", teleport_to);
+REGISTER_KEYBOARD_ACTION("walk_to", walk_to);
+REGISTER_KEYBOARD_ACTION("toggle_voice", toggle_voice);
+REGISTER_KEYBOARD_ACTION("voice_follow_key", voice_follow_key);
+#undef REGISTER_KEYBOARD_ACTION
+
+LLViewerInput::LLViewerInput()
+{
+    resetBindings();
+
+	for (S32 i = 0; i < KEY_COUNT; i++)
+	{
+		mKeyHandledByUI[i] = FALSE;
+    }
+    for (S32 i = 0; i < CLICK_COUNT; i++)
+    {
+        mMouseLevel[i] = MOUSE_STATE_SILENT;
+    }
+	// we want the UI to never see these keys so that they can always control the avatar/camera
+	for(KEY k = KEY_PAD_UP; k <= KEY_PAD_DIVIDE; k++) 
+	{
+		mKeysSkippedByUI.insert(k);	
+	}
+}
+
+BOOL LLViewerInput::modeFromString(const std::string& string, S32 *mode) const
+{
+	if (string == "FIRST_PERSON")
+	{
+		*mode = MODE_FIRST_PERSON;
+		return TRUE;
+	}
+	else if (string == "THIRD_PERSON")
+	{
+		*mode = MODE_THIRD_PERSON;
+		return TRUE;
+	}
+	else if (string == "EDIT")
+	{
+		*mode = MODE_EDIT;
+		return TRUE;
+	}
+	else if (string == "EDIT_AVATAR")
+	{
+		*mode = MODE_EDIT_AVATAR;
+		return TRUE;
+	}
+	else if (string == "SITTING")
+	{
+		*mode = MODE_SITTING;
+		return TRUE;
+	}
+	else
+	{
+		*mode = MODE_THIRD_PERSON;
+		return FALSE;
+	}
+}
+
+BOOL LLViewerInput::mouseFromString(const std::string& string, EMouseClickType *mode) const
+{
+    if (string == "LMB")
+    {
+        *mode = CLICK_LEFT;
+        return TRUE;
+    }
+    else if (string == "Double LMB")
+    {
+        *mode = CLICK_DOUBLELEFT;
+        return TRUE;
+    }
+    else if (string == "MMB")
+    {
+        *mode = CLICK_MIDDLE;
+        return TRUE;
+    }
+    else if (string == "MB4")
+    {
+        *mode = CLICK_BUTTON4;
+        return TRUE;
+    }
+    else if (string == "MB5")
+    {
+        *mode = CLICK_BUTTON5;
+        return TRUE;
+    }
+    else
+    {
+        *mode = CLICK_NONE;
+        return FALSE;
+    }
+}
+
+BOOL LLViewerInput::handleKey(KEY translated_key, MASK translated_mask, BOOL repeated)
+{
+	// check for re-map
+	EKeyboardMode mode = gViewerInput.getMode();
+	U32 keyidx = (translated_mask<<16) | translated_key;
+	key_remap_t::iterator iter = mRemapKeys[mode].find(keyidx);
+	if (iter != mRemapKeys[mode].end())
+	{
+		translated_key = (iter->second) & 0xff;
+		translated_mask = (iter->second)>>16;
+	}
+
+	// No repeats of F-keys
+	BOOL repeatable_key = (translated_key < KEY_F1 || translated_key > KEY_F12);
+	if (!repeatable_key && repeated)
+	{
+		return FALSE;
+	}
+
+	LL_DEBUGS("UserInput") << "keydown -" << translated_key << "-" << LL_ENDL;
+	// skip skipped keys
+	if(mKeysSkippedByUI.find(translated_key) != mKeysSkippedByUI.end()) 
+	{
+		mKeyHandledByUI[translated_key] = FALSE;
+		LL_INFOS("KeyboardHandling") << "Key wasn't handled by UI!" << LL_ENDL;
+	}
+	else
+	{
+		// it is sufficient to set this value once per call to handlekey
+		// without clearing it, as it is only used in the subsequent call to scanKey
+		mKeyHandledByUI[translated_key] = gViewerWindow->handleKey(translated_key, translated_mask); 
+		// mKeyHandledByUI is not what you think ... this indicates whether the UI has handled this keypress yet (any keypress)
+		// NOT whether some UI shortcut wishes to handle the keypress
+	  
+	}
+	return mKeyHandledByUI[translated_key];
+}
+
+BOOL LLViewerInput::handleKeyUp(KEY translated_key, MASK translated_mask)
+{
+	return gViewerWindow->handleKeyUp(translated_key, translated_mask);
+}
+
+BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, const bool ignore, const std::string& function_name)
+{
+	S32 index;
+	typedef boost::function<bool(EKeystate)> function_t;
+	function_t function = NULL;
+	std::string name;
+
+	// Allow remapping of F2-F12
+	if (function_name[0] == 'F')
+	{
+		int c1 = function_name[1] - '0';
+		int c2 = function_name[2] ? function_name[2] - '0' : -1;
+		if (c1 >= 0 && c1 <= 9 && c2 >= -1 && c2 <= 9)
+		{
+			int idx = c1;
+			if (c2 >= 0)
+				idx = idx*10 + c2;
+			if (idx >=2 && idx <= 12)
+			{
+				U32 keyidx = ((mask<<16)|key);
+				(mRemapKeys[mode])[keyidx] = ((0<<16)|(KEY_F1+(idx-1)));
+				return TRUE;
+			}
+		}
+	}
+
+	// Not remapped, look for a function
+	
+	function_t* result = LLKeyboardActionRegistry::getValue(function_name);
+	if (result)
+	{
+		function = *result;
+	}
+
+	if (!function)
+	{
+		LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
+		return FALSE;
+	}
+
+	// check for duplicate first and overwrite
+    if (ignore)
+    {
+        for (index = 0; index < mKeyIgnoreMaskCount[mode]; index++)
+        {
+            if (key == mKeyIgnoreMask[mode][index].mKey)
+                break;
+        }
+    }
+    else
+    {
+        for (index = 0; index < mKeyBindingCount[mode]; index++)
+        {
+            if (key == mKeyBindings[mode][index].mKey && mask == mKeyBindings[mode][index].mMask)
+                break;
+        }
+    }
+
+	if (index >= MAX_KEY_BINDINGS)
+	{
+		LL_ERRS() << "LLKeyboard::bindKey() - too many keys for mode " << mode << LL_ENDL;
+		return FALSE;
+	}
+
+	if (mode >= MODE_COUNT)
+	{
+		LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
+		return FALSE;
+	}
+
+    if (ignore)
+    {
+        mKeyIgnoreMask[mode][index].mKey = key;
+        mKeyIgnoreMask[mode][index].mFunction = function;
+
+        if (index == mKeyIgnoreMaskCount[mode])
+            mKeyIgnoreMaskCount[mode]++;
+    }
+    else
+    {
+        mKeyBindings[mode][index].mKey = key;
+        mKeyBindings[mode][index].mMask = mask;
+        mKeyBindings[mode][index].mFunction = function;
+
+        if (index == mKeyBindingCount[mode])
+            mKeyBindingCount[mode]++;
+    }
+
+	return TRUE;
+}
+
+BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const bool ignore, const std::string& function_name)
+{
+    S32 index;
+    typedef boost::function<bool(EKeystate)> function_t;
+    function_t function = NULL;
+
+    function_t* result = LLKeyboardActionRegistry::getValue(function_name);
+    if (result)
+    {
+        function = *result;
+    }
+
+    if (!function)
+    {
+        LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
+        return FALSE;
+    }
+
+    // check for duplicate first and overwrite
+    if (ignore)
+    {
+        for (index = 0; index < mMouseIgnoreMaskCount[mode]; index++)
+        {
+            if (mouse == mMouseIgnoreMask[mode][index].mMouse)
+                break;
+        }
+    }
+    else
+    {
+        for (index = 0; index < mMouseBindingCount[mode]; index++)
+        {
+            if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask)
+                break;
+        }
+    }
+
+    if (index >= MAX_KEY_BINDINGS)
+    {
+        LL_ERRS() << "LLKeyboard::bindKey() - too many keys for mode " << mode << LL_ENDL;
+        return FALSE;
+    }
+
+    if (mode >= MODE_COUNT)
+    {
+        LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
+        return FALSE;
+    }
+
+    if (ignore)
+    {
+        mMouseIgnoreMask[mode][index].mMouse = mouse;
+        mMouseIgnoreMask[mode][index].mFunction = function;
+
+        if (index == mMouseIgnoreMaskCount[mode])
+            mMouseIgnoreMaskCount[mode]++;
+    }
+    else
+    {
+        mMouseBindings[mode][index].mMouse = mouse;
+        mMouseBindings[mode][index].mMask = mask;
+        mMouseBindings[mode][index].mFunction = function;
+
+        if (index == mMouseBindingCount[mode])
+            mMouseBindingCount[mode]++;
+    }
+
+    return TRUE;
+}
+
+LLViewerInput::KeyBinding::KeyBinding()
+:	key("key"),
+	mouse("mouse"),
+	mask("mask"),
+	command("command"),
+	ignore("ignore", false)
+{}
+
+LLViewerInput::KeyMode::KeyMode()
+:	bindings("binding")
+{}
+
+LLViewerInput::Keys::Keys()
+:	first_person("first_person"),
+	third_person("third_person"),
+	edit("edit"),
+	sitting("sitting"),
+	edit_avatar("edit_avatar")
+{}
+
+void LLViewerInput::resetBindings()
+{
+    for (S32 i = 0; i < MODE_COUNT; i++)
+    {
+        mKeyBindingCount[i] = 0;
+        mKeyIgnoreMaskCount[i] = 0;
+        mMouseBindingCount[i] = 0;
+        mMouseIgnoreMaskCount[i] = 0;
+    }
+}
+
+S32 LLViewerInput::loadBindingsXML(const std::string& filename)
+{
+    resetBindings();
+
+	S32 binding_count = 0;
+	Keys keys;
+	LLSimpleXUIParser parser;
+
+	if (parser.readXUI(filename, keys) 
+		&& keys.validateBlock())
+	{
+		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 LLViewerInput::loadBindingMode(const LLViewerInput::KeyMode& keymode, S32 mode)
+{
+	S32 binding_count = 0;
+	for (LLInitParam::ParamIterator<KeyBinding>::const_iterator it = keymode.bindings.begin(), 
+			end_it = keymode.bindings.end();
+		it != end_it;
+		++it)
+	{
+        bool processed = false;
+        if (!it->key.getValue().empty())
+        {
+            KEY key;
+            LLKeyboard::keyFromString(it->key, &key);
+            if (key != KEY_NONE)
+            {
+                MASK mask;
+                bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;
+                LLKeyboard::maskFromString(it->mask, &mask);
+                bindKey(mode, key, mask, ignore, it->command);
+                processed = true;
+            }
+            else
+            {
+                LL_WARNS_ONCE() << "There might be issues in keybindings' file" << LL_ENDL;
+            }
+        }
+        if (!processed && it->mouse.isProvided() && !it->mouse.getValue().empty())
+        {
+            EMouseClickType mouse;
+            mouseFromString(it->mouse.getValue(), &mouse);
+            if (mouse != CLICK_NONE)
+            {
+                MASK mask;
+                bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;
+                LLKeyboard::maskFromString(it->mask, &mask);
+                bindMouse(mode, mouse, mask, ignore, it->command);
+                processed = true;
+            }
+            else
+            {
+                LL_WARNS_ONCE() << "There might be issues in keybindings' file" << LL_ENDL;
+            }
+        }
+        if (processed)
+        {
+            // total
+            binding_count++;
+        }
+	}
+
+	return binding_count;
+}
+
+EKeyboardMode LLViewerInput::getMode() const
+{
+	if ( gAgentCamera.cameraMouselook() )
+	{
+		return MODE_FIRST_PERSON;
+	}
+	else if ( gMorphView && gMorphView->getVisible())
+	{
+		return MODE_EDIT_AVATAR;
+	}
+	else if (isAgentAvatarValid() && gAgentAvatarp->isSitting())
+	{
+		return MODE_SITTING;
+	}
+	else
+	{
+		return MODE_THIRD_PERSON;
+	}
+}
+
+bool LLViewerInput::scanKey(const LLKeyboardBinding* binding,
+                               S32 binding_count,
+                               KEY key,
+                               MASK mask,
+                               BOOL key_down,
+                               BOOL key_up,
+                               BOOL key_level,
+                               bool repeat) const
+{
+	for (S32 i = 0; i < binding_count; i++)
+	{
+		if (binding[i].mKey == key)
+		{
+			if (binding[i].mMask == mask)
+			{
+				bool res = false;
+				if (key_down && !repeat)
+				{
+					// ...key went down this frame, call function
+					res = binding[i].mFunction( KEYSTATE_DOWN );
+					return true;
+				}
+				else if (key_up)
+				{
+					// ...key went down this frame, call function
+					res = binding[i].mFunction( KEYSTATE_UP );
+				}
+				else if (key_level)
+				{
+					// ...key held down from previous frame
+					// Not windows, just call the function.
+					res = binding[i].mFunction( KEYSTATE_LEVEL );
+				}//if
+				// Key+Mask combinations are supposed to be unique, so we won't find anything else
+				return res;
+			}//if
+		}//if
+	}//for
+	return false;
+}
+
+// Called from scanKeyboard.
+bool LLViewerInput::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) const
+{
+	if (LLApp::isExiting())
+	{
+		return;
+	}
+
+	S32 mode = getMode();
+	// Consider keyboard scanning as NOT mouse event. JC
+	MASK mask = gKeyboard->currentMask(FALSE);
+
+	if (mKeyHandledByUI[key])
+	{
+		return false;
+	}
+
+	// don't process key down on repeated keys
+	BOOL repeat = gKeyboard->getKeyRepeated(key);
+
+    bool res = scanKey(mKeyBindings[mode], mKeyBindingCount[mode], key, mask, key_down, key_up, key_level, repeat);
+    if (!res)
+    {
+        // Nothing found, try ignore list
+        res = scanKey(mKeyIgnoreMask[mode], mKeyIgnoreMaskCount[mode], key, MASK_NONE, key_down, key_up, key_level, repeat);
+    }
+
+    if (!res && agent_control_lbutton.canHandle(CLICK_NONE, key, mask))
+    {
+        if (key_down && !repeat)
+        {
+            res = agen_control_lbutton_handle(KEYSTATE_DOWN);
+        }
+        if (key_up)
+        {
+            res = agen_control_lbutton_handle(KEYSTATE_UP);
+        }
+    }
+    return res;
+}
+
+BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down)
+{
+    BOOL handled = gViewerWindow->handleAnyMouseClick(window_impl, pos, mask, clicktype, down);
+
+    if (clicktype != CLICK_NONE)
+    {
+        // Special case
+        // If UI doesn't handle double click, LMB click is issued, so supres LMB 'down' when doubleclick is set
+        // handle !down as if we are handling doubleclick
+
+        bool double_click_sp = (clicktype == CLICK_LEFT
+            && (mMouseLevel[CLICK_DOUBLELEFT] != MOUSE_STATE_SILENT)
+            && mMouseLevel[CLICK_LEFT] == MOUSE_STATE_SILENT);
+        if (double_click_sp && !down)
+        {
+            // Process doubleclick instead
+            clicktype = CLICK_DOUBLELEFT;
+        }
+
+
+        if (double_click_sp && down)
+        {
+            // Consume click.
+            // Due to handling, double click that is not handled will be immediately followed by LMB click
+        }
+        // If UI handled 'down', it should handle 'up' as well
+        // If we handle 'down' not by UI, then we should handle 'up'/'level' regardless of UI
+        else if (handled)
+        {
+            // UI handled new 'down' so iterupt whatever state we were in.
+            if (mMouseLevel[clicktype] != MOUSE_STATE_SILENT)
+            {
+                if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN)
+                {
+                    mMouseLevel[clicktype] = MOUSE_STATE_CLICK;
+                }
+                else
+                {
+                    mMouseLevel[clicktype] = MOUSE_STATE_UP;
+                }
+            }
+        }
+        else if (down)
+        {
+            if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN)
+            {
+                // this is repeated hit (mouse does not repeat event until release)
+                // for now treat rapid clicking like mouse being held
+                mMouseLevel[clicktype] = MOUSE_STATE_LEVEL;
+            }
+            else
+            {
+                mMouseLevel[clicktype] = MOUSE_STATE_DOWN;
+            }
+        }
+        else if (mMouseLevel[clicktype] != MOUSE_STATE_SILENT)
+        {
+            // Released mouse key
+            if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN)
+            {
+                mMouseLevel[clicktype] = MOUSE_STATE_CLICK;
+            }
+            else 
+            {
+                mMouseLevel[clicktype] = MOUSE_STATE_UP;
+            }
+        }
+    }
+
+    return handled;
+}
+
+bool LLViewerInput::scanMouse(const LLMouseBinding *binding, S32 binding_count, EMouseClickType mouse, MASK mask, EMouseState state) const
+{
+    for (S32 i = 0; i < binding_count; i++)
+    {
+        if (binding[i].mMouse == mouse && binding[i].mMask == mask)
+        {
+            bool res = false;
+            switch (state)
+            {
+            case MOUSE_STATE_DOWN:
+                res = binding[i].mFunction(KEYSTATE_DOWN);
+                break;
+            case MOUSE_STATE_CLICK:
+                // Button went down and up in scope of single frame
+                // might not work best with some functions,
+                // but some function need specific states specifically
+                res = binding[i].mFunction(KEYSTATE_DOWN);
+                res |= binding[i].mFunction(KEYSTATE_UP);
+                break;
+            case MOUSE_STATE_LEVEL:
+                res = binding[i].mFunction(KEYSTATE_LEVEL);
+                break;
+            case MOUSE_STATE_UP:
+                res = binding[i].mFunction(KEYSTATE_UP);
+                break;
+            default:
+                break;
+            }
+            // Key+Mask combinations are supposed to be unique, no need to continue
+            return res;
+        }
+    }
+    return false;
+}
+
+// todo: this recods key, scanMouse() triggers functions with EKeystate
+bool LLViewerInput::scanMouse(EMouseClickType click, EMouseState state) const
+{
+    bool res = false;
+    S32 mode = getMode();
+    MASK mask = gKeyboard->currentMask(TRUE);
+    res = scanMouse(mMouseBindings[mode], mMouseBindingCount[mode], click, mask, state);
+    if (!res)
+    {
+        res = scanMouse(mMouseIgnoreMask[mode], mMouseIgnoreMaskCount[mode], click, MASK_NONE, state);
+    }
+    // no user defined actions found or those actions can't handle the key/button, handle control if nessesary
+    if (!res && agent_control_lbutton.canHandle(click, KEY_NONE, mask))
+    {
+        switch (state)
+        {
+        case MOUSE_STATE_DOWN:
+            agen_control_lbutton_handle(KEYSTATE_DOWN);
+            res = true;
+            break;
+        case MOUSE_STATE_CLICK:
+            // might not work best with some functions,
+            // but some function need specific states too specifically
+            agen_control_lbutton_handle(KEYSTATE_DOWN);
+            agen_control_lbutton_handle(KEYSTATE_UP);
+            res = true;
+            break;
+        case MOUSE_STATE_UP:
+            agen_control_lbutton_handle(KEYSTATE_UP);
+            res = true;
+            break;
+        default:
+            break;
+        }
+    }
+    return res;
+}
+
+void LLViewerInput::scanMouse()
+{
+    for (S32 i = 0; i < CLICK_COUNT; i++)
+    {
+        if (mMouseLevel[i] != MOUSE_STATE_SILENT)
+        {
+            scanMouse((EMouseClickType)i, mMouseLevel[i]);
+            if (mMouseLevel[i] == MOUSE_STATE_DOWN)
+            {
+                // mouse doesn't support 'continued' state, so after handling, switch to LEVEL
+                mMouseLevel[i] = MOUSE_STATE_LEVEL;
+            }
+            else if (mMouseLevel[i] == MOUSE_STATE_UP || mMouseLevel[i] == MOUSE_STATE_CLICK)
+            {
+                mMouseLevel[i] = MOUSE_STATE_SILENT;
+            }
+        }
+    }
+}
diff --git a/indra/newview/llviewerinput.h b/indra/newview/llviewerinput.h
new file mode 100644
index 0000000000..d18a61eaf0
--- /dev/null
+++ b/indra/newview/llviewerinput.h
@@ -0,0 +1,193 @@
+/** 
+ * @file llviewerinput.h
+ * @brief LLViewerInput class header file
+ *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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_LLVIEWERINPUT_H
+#define LL_LLVIEWERINPUT_H
+
+#include "llkeyboard.h" // For EKeystate
+#include "llinitparam.h"
+
+const S32 MAX_NAMED_FUNCTIONS = 100;
+const S32 MAX_KEY_BINDINGS = 128; // was 60
+
+class LLNamedFunction
+{
+public:
+	LLNamedFunction() : mFunction(NULL) { };
+	~LLNamedFunction() { };
+
+	std::string	mName;
+	LLKeyFunc	mFunction;
+};
+
+class LLKeyboardBinding
+{
+public:
+    KEY				mKey;
+    MASK			mMask;
+    bool			mIgnoreMask; // whether CTRL/ALT/SHIFT should be checked
+
+    LLKeyFunc		mFunction;
+};
+
+class LLMouseBinding
+{
+public:
+    EMouseClickType	mMouse;
+    MASK			mMask;
+    bool			mIgnoreMask; // whether CTRL/ALT/SHIFT should be checked
+
+    LLKeyFunc		mFunction;
+};
+
+
+typedef enum e_keyboard_mode
+{
+	MODE_FIRST_PERSON,
+	MODE_THIRD_PERSON,
+	MODE_EDIT,
+	MODE_EDIT_AVATAR,
+	MODE_SITTING,
+	MODE_COUNT
+} EKeyboardMode;
+
+class LLWindow;
+
+void bind_keyboard_functions();
+
+class LLViewerInput
+{
+public:
+	struct KeyBinding : public LLInitParam::Block<KeyBinding>
+	{
+		Mandatory<std::string>	key,
+								mask,
+								command;
+		Optional<std::string>	mouse; // Note, not mandatory for the sake of backward campatibility
+		Optional<bool>			ignore;
+
+		KeyBinding();
+	};
+
+	struct KeyMode : public LLInitParam::Block<KeyMode>
+	{
+		Multiple<KeyBinding>		bindings;
+
+		KeyMode();
+	};
+
+	struct Keys : public LLInitParam::Block<Keys>
+	{
+		Optional<KeyMode>	first_person,
+							third_person,
+							edit,
+							sitting,
+							edit_avatar;
+
+		Keys();
+	};
+
+	LLViewerInput();
+
+	BOOL			handleKey(KEY key, MASK mask, BOOL repeated);
+	BOOL			handleKeyUp(KEY key, MASK mask);
+
+	S32				loadBindingsXML(const std::string& filename);										// returns number bound, 0 on error
+	EKeyboardMode	getMode() const;
+
+	BOOL			modeFromString(const std::string& string, S32 *mode) const;			// False on failure
+	BOOL			mouseFromString(const std::string& string, EMouseClickType *mode) const;// False on failure
+
+    bool            scanKey(KEY key,
+                            BOOL key_down,
+                            BOOL key_up,
+                            BOOL key_level) const;
+
+    // handleMouse() records state, scanMouse() goes through states, scanMouse(click) processes individual saved states after UI is done with them
+    BOOL            handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down);
+    void            scanMouse();
+
+private:
+    bool            scanKey(const LLKeyboardBinding* binding,
+                            S32 binding_count,
+                            KEY key,
+                            MASK mask,
+                            BOOL key_down,
+                            BOOL key_up,
+                            BOOL key_level,
+                            bool repeat) const;
+
+    enum EMouseState
+    {
+        MOUSE_STATE_DOWN, // key down this frame
+        MOUSE_STATE_CLICK, // key went up and down in scope of same frame
+        MOUSE_STATE_LEVEL, // clicked again fast, or never released
+        MOUSE_STATE_UP, // went up this frame
+        MOUSE_STATE_SILENT // notified about 'up', do not notify again
+    };
+    bool			scanMouse(EMouseClickType click, EMouseState state) const;
+    bool            scanMouse(const LLMouseBinding *binding,
+                          S32 binding_count,
+                          EMouseClickType mouse,
+                          MASK mask,
+                          EMouseState state) const;
+
+    S32				loadBindingMode(const LLViewerInput::KeyMode& keymode, S32 mode);
+    BOOL			bindKey(const S32 mode, const KEY key, const MASK mask, const bool ignore, const std::string& function_name);
+    BOOL			bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const bool ignore, const std::string& function_name);
+    void			resetBindings();
+
+	// Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here
+    // We process specific keys first, then keys that should ignore mask.
+    // This way with W+ignore defined to 'forward' and with ctrl+W tied to camera,
+    // pressing undefined Shift+W will do 'forward', yet ctrl+W will do 'camera forward'
+    // With A defined to 'turn', shift+A defined to strafe, pressing Shift+W+A will do strafe+forward
+
+    // TODO: at some point it is better to remake this, especially keyaboard part
+    // would be much better to send to functions actual state of the button than
+    // to send what we think function wants based on collection of bools (mKeyRepeated, mKeyLevel, mKeyDown)
+    S32				mKeyBindingCount[MODE_COUNT];
+    S32				mKeyIgnoreMaskCount[MODE_COUNT];
+    S32				mMouseBindingCount[MODE_COUNT];
+    S32				mMouseIgnoreMaskCount[MODE_COUNT];
+    LLKeyboardBinding	mKeyBindings[MODE_COUNT][MAX_KEY_BINDINGS];
+    LLKeyboardBinding	mKeyIgnoreMask[MODE_COUNT][MAX_KEY_BINDINGS];
+    LLMouseBinding		mMouseBindings[MODE_COUNT][MAX_KEY_BINDINGS];
+    LLMouseBinding		mMouseIgnoreMask[MODE_COUNT][MAX_KEY_BINDINGS];
+
+	typedef std::map<U32, U32> key_remap_t;
+	key_remap_t		mRemapKeys[MODE_COUNT];
+	std::set<KEY>	mKeysSkippedByUI;
+	BOOL			mKeyHandledByUI[KEY_COUNT];		// key processed successfully by UI
+
+    // This is indentical to what llkeyboard does (mKeyRepeated, mKeyLevel, mKeyDown e t c),
+    // just instead of remembering individually as bools,  we record state as enum
+    EMouseState		mMouseLevel[CLICK_COUNT];	// records of key state
+};
+
+extern LLViewerInput gViewerInput;
+
+#endif // LL_LLVIEWERINPUT_H
diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp
deleted file mode 100644
index 9755d3444a..0000000000
--- a/indra/newview/llviewerkeyboard.cpp
+++ /dev/null
@@ -1,1462 +0,0 @@
-/** 
- * @file llviewerkeyboard.cpp
- * @brief LLViewerKeyboard class implementation
- *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llviewerkeyboard.h"
-
-#include "llappviewer.h"
-#include "llfloaterreg.h"
-#include "llmath.h"
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "llfloaterimnearbychat.h"
-#include "llfocusmgr.h"
-#include "llkeybind.h" // LLKeyData
-#include "llmorphview.h"
-#include "llmoveview.h"
-#include "lltoolfocus.h"
-#include "lltoolpie.h"
-#include "llviewercontrol.h"
-#include "llviewerwindow.h"
-#include "llvoavatarself.h"
-#include "llfloatercamera.h"
-#include "llinitparam.h"
-
-//
-// Constants
-//
-
-const F32 FLY_TIME = 0.5f;
-const F32 FLY_FRAMES = 4;
-
-const F32 NUDGE_TIME = 0.25f;  // in seconds
-const S32 NUDGE_FRAMES = 2;
-const F32 ORBIT_NUDGE_RATE = 0.05f;  // fraction of normal speed
-
-const LLKeyData agent_control_lbutton(CLICK_LEFT, KEY_NONE, MASK_NONE, true);
-
-struct LLKeyboardActionRegistry 
-:	public LLRegistrySingleton<std::string, boost::function<bool (EKeystate keystate)>, LLKeyboardActionRegistry>
-{
-	LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry);
-};
-
-LLViewerKeyboard gViewerKeyboard;
-
-bool agent_jump( EKeystate s )
-{
-	static BOOL first_fly_attempt(TRUE);
-	if (KEYSTATE_UP == s)
-	{
-		first_fly_attempt = TRUE;
-		return true;
-	}
-	F32 time = gKeyboard->getCurKeyElapsedTime();
-	S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
-
-	if( time < FLY_TIME 
-		|| frame_count <= FLY_FRAMES 
-		|| gAgent.upGrabbed()
-		|| !gSavedSettings.getBOOL("AutomaticFly"))
-	{
-		gAgent.moveUp(1);
-	}
-	else
-	{
-		gAgent.setFlying(TRUE, first_fly_attempt);
-		first_fly_attempt = FALSE;
-		gAgent.moveUp(1);
-	}
-	return true;
-}
-
-bool agent_push_down( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgent.moveUp(-1);
-	return true;
-}
-
-static void agent_check_temporary_run(LLAgent::EDoubleTapRunMode mode)
-{
-	if (gAgent.mDoubleTapRunMode == mode &&
-		gAgent.getRunning() &&
-		!gAgent.getAlwaysRun())
-	{
-		// Turn off temporary running.
-		gAgent.clearRunning();
-		gAgent.sendWalkRun(gAgent.getRunning());
-	}
-}
-
-static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode mode)
-{
-	if (KEYSTATE_UP == s)
-	{
-		// Note: in case shift is already released, slide left/right run
-		// will be released in agent_turn_left()/agent_turn_right()
-		agent_check_temporary_run(mode);
-	}
-	else if (gSavedSettings.getBOOL("AllowTapTapHoldRun") &&
-		 KEYSTATE_DOWN == s &&
-		 !gAgent.getRunning())
-	{
-		if (gAgent.mDoubleTapRunMode == mode &&
-		    gAgent.mDoubleTapRunTimer.getElapsedTimeF32() < NUDGE_TIME)
-		{
-			// Same walk-key was pushed again quickly; this is a
-			// double-tap so engage temporary running.
-			gAgent.setRunning();
-			gAgent.sendWalkRun(gAgent.getRunning());
-		}
-
-		// Pressing any walk-key resets the double-tap timer
-		gAgent.mDoubleTapRunTimer.reset();
-		gAgent.mDoubleTapRunMode = mode;
-	}
-}
-
-static void agent_push_forwardbackward( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode )
-{
-	agent_handle_doubletap_run(s, mode);
-	if (KEYSTATE_UP == s) return;
-
-	F32 time = gKeyboard->getCurKeyElapsedTime();
-	S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
-
-	if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES)
-	{
-		gAgent.moveAtNudge(direction);
-	}
-	else
-	{
-		gAgent.moveAt(direction);
-	}
-}
-
-bool camera_move_forward( EKeystate s );
-
-bool agent_push_forward( EKeystate s )
-{
-	if(gAgent.isMovementLocked()) return true;
-
-	//in free camera control mode we need to intercept keyboard events for avatar movements
-	if (LLFloaterCamera::inFreeCameraMode())
-	{
-		camera_move_forward(s);
-	}
-	else
-	{
-		agent_push_forwardbackward(s, 1, LLAgent::DOUBLETAP_FORWARD);
-	}
-	return true;
-}
-
-bool camera_move_backward( EKeystate s );
-
-bool agent_push_backward( EKeystate s )
-{
-	if(gAgent.isMovementLocked()) return true;
-
-	//in free camera control mode we need to intercept keyboard events for avatar movements
-	if (LLFloaterCamera::inFreeCameraMode())
-	{
-		camera_move_backward(s);
-	}
-	else if (!gAgent.backwardGrabbed() && gAgentAvatarp->isSitting() && gSavedSettings.getBOOL("LeaveMouselook"))
-	{
-		gAgentCamera.changeCameraToThirdPerson();
-	}
-	else
-	{
-		agent_push_forwardbackward(s, -1, LLAgent::DOUBLETAP_BACKWARD);
-	}
-	return true;
-}
-
-static void agent_slide_leftright( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode )
-{
-	agent_handle_doubletap_run(s, mode);
-	if( KEYSTATE_UP == s ) return;
-	F32 time = gKeyboard->getCurKeyElapsedTime();
-	S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
-
-	if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES)
-	{
-		gAgent.moveLeftNudge(direction);
-	}
-	else
-	{
-		gAgent.moveLeft(direction);
-	}
-}
-
-
-bool agent_slide_left( EKeystate s )
-{
-	if(gAgent.isMovementLocked()) return true;
-	agent_slide_leftright(s, 1, LLAgent::DOUBLETAP_SLIDELEFT);
-	return true;
-}
-
-
-bool agent_slide_right( EKeystate s )
-{
-	if(gAgent.isMovementLocked()) return true;
-	agent_slide_leftright(s, -1, LLAgent::DOUBLETAP_SLIDERIGHT);
-	return true;
-}
-
-bool camera_spin_around_cw( EKeystate s );
-
-bool agent_turn_left(EKeystate s)
-{
-	//in free camera control mode we need to intercept keyboard events for avatar movements
-	if (LLFloaterCamera::inFreeCameraMode())
-	{
-		camera_spin_around_cw(s);
-		return true;
-	}
-
-	if(gAgent.isMovementLocked()) return false;
-
-	if (LLToolCamera::getInstance()->mouseSteerMode())
-	{
-		agent_slide_left(s);
-	}
-	else
-	{
-		if (KEYSTATE_UP == s)
-		{
-			// Check temporary running. In case user released 'left' key with shift already released.
-			agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDELEFT);
-			return true;
-		}
-		F32 time = gKeyboard->getCurKeyElapsedTime();
-		gAgent.moveYaw( LLFloaterMove::getYawRate( time ) );
-	}
-	return true;
-}
-
-bool camera_spin_around_ccw( EKeystate s );
-
-bool agent_turn_right( EKeystate s )
-{
-	//in free camera control mode we need to intercept keyboard events for avatar movements
-	if (LLFloaterCamera::inFreeCameraMode())
-	{
-		camera_spin_around_ccw(s);
-		return true;
-	}
-
-	if(gAgent.isMovementLocked()) return false;
-
-	if (LLToolCamera::getInstance()->mouseSteerMode())
-	{
-		agent_slide_right(s);
-	}
-	else
-	{
-		if (KEYSTATE_UP == s)
-		{
-			// Check temporary running. In case user released 'right' key with shift already released.
-			agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDERIGHT);
-			return true;
-		}
-		F32 time = gKeyboard->getCurKeyElapsedTime();
-		gAgent.moveYaw( -LLFloaterMove::getYawRate( time ) );
-	}
-	return true;
-}
-
-bool agent_look_up( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgent.movePitch(-1);
-	//gAgent.rotate(-2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
-	return true;
-}
-
-
-bool agent_look_down( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgent.movePitch(1);
-	//gAgent.rotate(2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
-	return true;
-}
-
-bool agent_toggle_fly( EKeystate s )
-{
-	// Only catch the edge
-	if (KEYSTATE_DOWN == s )
-	{
-		LLAgent::toggleFlying();
-	}
-	return true;
-}
-
-F32 get_orbit_rate()
-{
-	F32 time = gKeyboard->getCurKeyElapsedTime();
-	if( time < NUDGE_TIME )
-	{
-		F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME;
-		//LL_INFOS() << rate << LL_ENDL;
-		return rate;
-	}
-	else
-	{
-		return 1;
-	}
-}
-
-bool camera_spin_around_ccw( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
-	return true;
-}
-
-
-bool camera_spin_around_cw( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setOrbitRightKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_spin_around_ccw_sitting( EKeystate s )
-{
-	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT ) return true;
-	if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning())
-	{
-		//send keystrokes, but do not change camera
-		agent_turn_right(s);
-	}
-	else
-	{
-		//change camera but do not send keystrokes
-		gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
-	}
-	return true;
-}
-
-
-bool camera_spin_around_cw_sitting( EKeystate s )
-{
-	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT ) return true;
-	if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning())
-	{
-		//send keystrokes, but do not change camera
-		agent_turn_left(s);
-	}
-	else
-	{
-		//change camera but do not send keystrokes
-		gAgentCamera.setOrbitRightKey( get_orbit_rate() );
-	}
-	return true;
-}
-
-
-bool camera_spin_over( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setOrbitUpKey( get_orbit_rate() );
-	return true;
-}
-
-
-bool camera_spin_under( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setOrbitDownKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_spin_over_sitting( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	if (gAgent.upGrabbed() || gAgentCamera.sitCameraEnabled())
-	{
-		//send keystrokes, but do not change camera
-		agent_jump(s);
-	}
-	else
-	{
-		//change camera but do not send keystrokes
-		gAgentCamera.setOrbitUpKey( get_orbit_rate() );
-	}
-	return true;
-}
-
-
-bool camera_spin_under_sitting( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	if (gAgent.downGrabbed() || gAgentCamera.sitCameraEnabled())
-	{
-		//send keystrokes, but do not change camera
-		agent_push_down(s);
-	}
-	else
-	{
-		//change camera but do not send keystrokes
-		gAgentCamera.setOrbitDownKey( get_orbit_rate() );
-	}
-	return true;
-}
-
-bool camera_move_forward( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setOrbitInKey( get_orbit_rate() );
-	return true;
-}
-
-
-bool camera_move_backward( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setOrbitOutKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_move_forward_sitting( EKeystate s )
-{
-	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD ) return true;
-	if (gAgent.forwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun()))
-	{
-		agent_push_forward(s);
-	}
-	else
-	{
-		gAgentCamera.setOrbitInKey( get_orbit_rate() );
-	}
-	return true;
-}
-
-
-bool camera_move_backward_sitting( EKeystate s )
-{
-	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD ) return true;
-
-	if (gAgent.backwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun()))
-	{
-		agent_push_backward(s);
-	}
-	else
-	{
-		gAgentCamera.setOrbitOutKey( get_orbit_rate() );
-	}
-	return true;
-}
-
-bool camera_pan_up( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setPanUpKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_pan_down( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setPanDownKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_pan_left( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setPanLeftKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_pan_right( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setPanRightKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_pan_in( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setPanInKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_pan_out( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setPanOutKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_move_forward_fast( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setOrbitInKey(2.5f);
-	return true;
-}
-
-bool camera_move_backward_fast( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setOrbitOutKey(2.5f);
-	return true;
-}
-
-
-bool edit_avatar_spin_ccw( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gMorphView->setCameraDrivenByKeys( TRUE );
-	gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
-	//gMorphView->orbitLeft( get_orbit_rate() );
-	return true;
-}
-
-
-bool edit_avatar_spin_cw( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gMorphView->setCameraDrivenByKeys( TRUE );
-	gAgentCamera.setOrbitRightKey( get_orbit_rate() );
-	//gMorphView->orbitRight( get_orbit_rate() );
-	return true;
-}
-
-bool edit_avatar_spin_over( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gMorphView->setCameraDrivenByKeys( TRUE );
-	gAgentCamera.setOrbitUpKey( get_orbit_rate() );
-	//gMorphView->orbitUp( get_orbit_rate() );
-	return true;
-}
-
-
-bool edit_avatar_spin_under( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gMorphView->setCameraDrivenByKeys( TRUE );
-	gAgentCamera.setOrbitDownKey( get_orbit_rate() );
-	//gMorphView->orbitDown( get_orbit_rate() );
-	return true;
-}
-
-bool edit_avatar_move_forward( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gMorphView->setCameraDrivenByKeys( TRUE );
-	gAgentCamera.setOrbitInKey( get_orbit_rate() );
-	//gMorphView->orbitIn();
-	return true;
-}
-
-
-bool edit_avatar_move_backward( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gMorphView->setCameraDrivenByKeys( TRUE );
-	gAgentCamera.setOrbitOutKey( get_orbit_rate() );
-	//gMorphView->orbitOut();
-	return true;
-}
-
-bool stop_moving( EKeystate s )
-{
-	if( KEYSTATE_DOWN != s  ) return true;
-	// stop agent
-	gAgent.setControlFlags(AGENT_CONTROL_STOP);
-
-	// cancel autopilot
-	gAgent.stopAutoPilot();
-	return true;
-}
-
-bool start_chat( EKeystate s )
-{
-    if (LLAppViewer::instance()->quitRequested())
-    {
-        return true; // can't talk, gotta go, kthxbye!
-    }
-    if (KEYSTATE_DOWN != s) return true;
-
-	// start chat
-	LLFloaterIMNearbyChat::startChat(NULL);
-	return true;
-}
-
-bool start_gesture( EKeystate s )
-{
-	LLUICtrl* focus_ctrlp = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
-	if (KEYSTATE_UP == s &&
-		! (focus_ctrlp && focus_ctrlp->acceptsTextInput()))
-	{
- 		if ((LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"))->getCurrentChat().empty())
- 		{
- 			// No existing chat in chat editor, insert '/'
- 			LLFloaterIMNearbyChat::startChat("/");
- 		}
- 		else
- 		{
- 			// Don't overwrite existing text in chat editor
- 			LLFloaterIMNearbyChat::startChat(NULL);
- 		}
-	}
-	return true;
-}
-
-bool toggle_run(EKeystate s)
-{
-    if (KEYSTATE_DOWN != s) return true;
-    bool run = gAgent.getAlwaysRun();
-    if (run)
-    {
-        gAgent.clearAlwaysRun();
-        gAgent.clearRunning();
-    }
-    else
-    {
-        gAgent.setAlwaysRun();
-        gAgent.setRunning();
-    }
-    gAgent.sendWalkRun(!run);
-	return true;
-}
-
-bool toggle_sit(EKeystate s)
-{
-    if (KEYSTATE_DOWN != s) return true;
-    if (gAgent.isSitting())
-    {
-        gAgent.standUp();
-    }
-    else
-    {
-        gAgent.sitDown();
-    }
-	return true;
-}
-
-bool toggle_pause_media(EKeystate s) // analogue of play/pause button in top bar
-{
-    if (KEYSTATE_DOWN != s) return true;
-    bool pause = LLViewerMedia::isAnyMediaPlaying();
-    LLViewerMedia::setAllMediaPaused(pause);
-    return true;
-}
-
-bool toggle_enable_media(EKeystate s)
-{
-    if (KEYSTATE_DOWN != s) return true;
-    bool pause = LLViewerMedia::isAnyMediaPlaying() || LLViewerMedia::isAnyMediaShowing();
-    LLViewerMedia::setAllMediaEnabled(!pause);
-    return true;
-}
-
-bool walk_to(EKeystate s)
-{
-    if (KEYSTATE_DOWN != s) return true;
-    return LLToolPie::getInstance()->walkToClickedLocation();
-}
-
-bool teleport_to(EKeystate s)
-{
-    if (KEYSTATE_DOWN != s) return true;
-    return LLToolPie::getInstance()->teleportToClickedLocation();
-}
-
-bool toggle_voice(EKeystate s)
-{
-    if (KEYSTATE_DOWN != s) return true;
-    if (!LLAgent::isActionAllowed("speak")) return false;
-    LLVoiceClient::getInstance()->toggleUserPTTState();
-    return true;
-}
-
-bool voice_follow_key(EKeystate s)
-{
-    if (KEYSTATE_DOWN == s)
-    {
-        if (!LLAgent::isActionAllowed("speak")) return false;
-        LLVoiceClient::getInstance()->setUserPTTState(true);
-        return true;
-    }
-    else if (KEYSTATE_UP == s && LLVoiceClient::getInstance()->getUserPTTState())
-    {
-        LLVoiceClient::getInstance()->setUserPTTState(false);
-        return true;
-    }
-    return false;
-}
-
-bool agen_control_lbutton_handle(EKeystate s)
-{
-    switch (s)
-    {
-    case KEYSTATE_DOWN:
-        gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN);
-        break;
-    case KEYSTATE_UP:
-        gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP);
-        break;
-    default:
-        break;
-    }
-    return true;
-}
-
-#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);
-REGISTER_KEYBOARD_ACTION("push_forward", agent_push_forward);
-REGISTER_KEYBOARD_ACTION("push_backward", agent_push_backward);
-REGISTER_KEYBOARD_ACTION("look_up", agent_look_up);
-REGISTER_KEYBOARD_ACTION("look_down", agent_look_down);
-REGISTER_KEYBOARD_ACTION("toggle_fly", agent_toggle_fly);
-REGISTER_KEYBOARD_ACTION("turn_left", agent_turn_left);
-REGISTER_KEYBOARD_ACTION("turn_right", agent_turn_right);
-REGISTER_KEYBOARD_ACTION("slide_left", agent_slide_left);
-REGISTER_KEYBOARD_ACTION("slide_right", agent_slide_right);
-REGISTER_KEYBOARD_ACTION("spin_around_ccw", camera_spin_around_ccw);
-REGISTER_KEYBOARD_ACTION("spin_around_cw", camera_spin_around_cw);
-REGISTER_KEYBOARD_ACTION("spin_around_ccw_sitting", camera_spin_around_ccw_sitting);
-REGISTER_KEYBOARD_ACTION("spin_around_cw_sitting", camera_spin_around_cw_sitting);
-REGISTER_KEYBOARD_ACTION("spin_over", camera_spin_over);
-REGISTER_KEYBOARD_ACTION("spin_under", camera_spin_under);
-REGISTER_KEYBOARD_ACTION("spin_over_sitting", camera_spin_over_sitting);
-REGISTER_KEYBOARD_ACTION("spin_under_sitting", camera_spin_under_sitting);
-REGISTER_KEYBOARD_ACTION("move_forward", camera_move_forward);
-REGISTER_KEYBOARD_ACTION("move_backward", camera_move_backward);
-REGISTER_KEYBOARD_ACTION("move_forward_sitting", camera_move_forward_sitting);
-REGISTER_KEYBOARD_ACTION("move_backward_sitting", camera_move_backward_sitting);
-REGISTER_KEYBOARD_ACTION("pan_up", camera_pan_up);
-REGISTER_KEYBOARD_ACTION("pan_down", camera_pan_down);
-REGISTER_KEYBOARD_ACTION("pan_left", camera_pan_left);
-REGISTER_KEYBOARD_ACTION("pan_right", camera_pan_right);
-REGISTER_KEYBOARD_ACTION("pan_in", camera_pan_in);
-REGISTER_KEYBOARD_ACTION("pan_out", camera_pan_out);
-REGISTER_KEYBOARD_ACTION("move_forward_fast", camera_move_forward_fast);
-REGISTER_KEYBOARD_ACTION("move_backward_fast", camera_move_backward_fast);
-REGISTER_KEYBOARD_ACTION("edit_avatar_spin_ccw", edit_avatar_spin_ccw);
-REGISTER_KEYBOARD_ACTION("edit_avatar_spin_cw", edit_avatar_spin_cw);
-REGISTER_KEYBOARD_ACTION("edit_avatar_spin_over", edit_avatar_spin_over);
-REGISTER_KEYBOARD_ACTION("edit_avatar_spin_under", edit_avatar_spin_under);
-REGISTER_KEYBOARD_ACTION("edit_avatar_move_forward", edit_avatar_move_forward);
-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_run", toggle_run);
-REGISTER_KEYBOARD_ACTION("toggle_sit", toggle_sit);
-REGISTER_KEYBOARD_ACTION("toggle_pause_media", toggle_pause_media);
-REGISTER_KEYBOARD_ACTION("toggle_enable_media", toggle_enable_media);
-REGISTER_KEYBOARD_ACTION("teleport_to", teleport_to);
-REGISTER_KEYBOARD_ACTION("walk_to", walk_to);
-REGISTER_KEYBOARD_ACTION("toggle_voice", toggle_voice);
-REGISTER_KEYBOARD_ACTION("voice_follow_key", voice_follow_key);
-#undef REGISTER_KEYBOARD_ACTION
-
-LLViewerKeyboard::LLViewerKeyboard()
-{
-    resetBindings();
-
-	for (S32 i = 0; i < KEY_COUNT; i++)
-	{
-		mKeyHandledByUI[i] = FALSE;
-    }
-    for (S32 i = 0; i < CLICK_COUNT; i++)
-    {
-        mMouseLevel[i] = MOUSE_STATE_SILENT;
-    }
-	// we want the UI to never see these keys so that they can always control the avatar/camera
-	for(KEY k = KEY_PAD_UP; k <= KEY_PAD_DIVIDE; k++) 
-	{
-		mKeysSkippedByUI.insert(k);	
-	}
-}
-
-BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode) const
-{
-	if (string == "FIRST_PERSON")
-	{
-		*mode = MODE_FIRST_PERSON;
-		return TRUE;
-	}
-	else if (string == "THIRD_PERSON")
-	{
-		*mode = MODE_THIRD_PERSON;
-		return TRUE;
-	}
-	else if (string == "EDIT")
-	{
-		*mode = MODE_EDIT;
-		return TRUE;
-	}
-	else if (string == "EDIT_AVATAR")
-	{
-		*mode = MODE_EDIT_AVATAR;
-		return TRUE;
-	}
-	else if (string == "SITTING")
-	{
-		*mode = MODE_SITTING;
-		return TRUE;
-	}
-	else
-	{
-		*mode = MODE_THIRD_PERSON;
-		return FALSE;
-	}
-}
-
-BOOL LLViewerKeyboard::mouseFromString(const std::string& string, EMouseClickType *mode) const
-{
-    if (string == "LMB")
-    {
-        *mode = CLICK_LEFT;
-        return TRUE;
-    }
-    else if (string == "Double LMB")
-    {
-        *mode = CLICK_DOUBLELEFT;
-        return TRUE;
-    }
-    else if (string == "MMB")
-    {
-        *mode = CLICK_MIDDLE;
-        return TRUE;
-    }
-    else if (string == "MB4")
-    {
-        *mode = CLICK_BUTTON4;
-        return TRUE;
-    }
-    else if (string == "MB5")
-    {
-        *mode = CLICK_BUTTON5;
-        return TRUE;
-    }
-    else
-    {
-        *mode = CLICK_NONE;
-        return FALSE;
-    }
-}
-
-BOOL LLViewerKeyboard::handleKey(KEY translated_key,  MASK translated_mask, BOOL repeated)
-{
-	// check for re-map
-	EKeyboardMode mode = gViewerKeyboard.getMode();
-	U32 keyidx = (translated_mask<<16) | translated_key;
-	key_remap_t::iterator iter = mRemapKeys[mode].find(keyidx);
-	if (iter != mRemapKeys[mode].end())
-	{
-		translated_key = (iter->second) & 0xff;
-		translated_mask = (iter->second)>>16;
-	}
-
-	// No repeats of F-keys
-	BOOL repeatable_key = (translated_key < KEY_F1 || translated_key > KEY_F12);
-	if (!repeatable_key && repeated)
-	{
-		return FALSE;
-	}
-
-	LL_DEBUGS("UserInput") << "keydown -" << translated_key << "-" << LL_ENDL;
-	// skip skipped keys
-	if(mKeysSkippedByUI.find(translated_key) != mKeysSkippedByUI.end()) 
-	{
-		mKeyHandledByUI[translated_key] = FALSE;
-		LL_INFOS("KeyboardHandling") << "Key wasn't handled by UI!" << LL_ENDL;
-	}
-	else
-	{
-		// it is sufficient to set this value once per call to handlekey
-		// without clearing it, as it is only used in the subsequent call to scanKey
-		mKeyHandledByUI[translated_key] = gViewerWindow->handleKey(translated_key, translated_mask); 
-		// mKeyHandledByUI is not what you think ... this indicates whether the UI has handled this keypress yet (any keypress)
-		// NOT whether some UI shortcut wishes to handle the keypress
-	  
-	}
-	return mKeyHandledByUI[translated_key];
-}
-
-BOOL LLViewerKeyboard::handleKeyUp(KEY translated_key, MASK translated_mask)
-{
-	return gViewerWindow->handleKeyUp(translated_key, translated_mask);
-}
-
-BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const bool ignore, const std::string& function_name)
-{
-	S32 index;
-	typedef boost::function<bool(EKeystate)> function_t;
-	function_t function = NULL;
-	std::string name;
-
-	// Allow remapping of F2-F12
-	if (function_name[0] == 'F')
-	{
-		int c1 = function_name[1] - '0';
-		int c2 = function_name[2] ? function_name[2] - '0' : -1;
-		if (c1 >= 0 && c1 <= 9 && c2 >= -1 && c2 <= 9)
-		{
-			int idx = c1;
-			if (c2 >= 0)
-				idx = idx*10 + c2;
-			if (idx >=2 && idx <= 12)
-			{
-				U32 keyidx = ((mask<<16)|key);
-				(mRemapKeys[mode])[keyidx] = ((0<<16)|(KEY_F1+(idx-1)));
-				return TRUE;
-			}
-		}
-	}
-
-	// Not remapped, look for a function
-	
-	function_t* result = LLKeyboardActionRegistry::getValue(function_name);
-	if (result)
-	{
-		function = *result;
-	}
-
-	if (!function)
-	{
-		LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
-		return FALSE;
-	}
-
-	// check for duplicate first and overwrite
-    if (ignore)
-    {
-        for (index = 0; index < mKeyIgnoreMaskCount[mode]; index++)
-        {
-            if (key == mKeyIgnoreMask[mode][index].mKey)
-                break;
-        }
-    }
-    else
-    {
-        for (index = 0; index < mKeyBindingCount[mode]; index++)
-        {
-            if (key == mKeyBindings[mode][index].mKey && mask == mKeyBindings[mode][index].mMask)
-                break;
-        }
-    }
-
-	if (index >= MAX_KEY_BINDINGS)
-	{
-		LL_ERRS() << "LLKeyboard::bindKey() - too many keys for mode " << mode << LL_ENDL;
-		return FALSE;
-	}
-
-	if (mode >= MODE_COUNT)
-	{
-		LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
-		return FALSE;
-	}
-
-    if (ignore)
-    {
-        mKeyIgnoreMask[mode][index].mKey = key;
-        mKeyIgnoreMask[mode][index].mFunction = function;
-
-        if (index == mKeyIgnoreMaskCount[mode])
-            mKeyIgnoreMaskCount[mode]++;
-    }
-    else
-    {
-        mKeyBindings[mode][index].mKey = key;
-        mKeyBindings[mode][index].mMask = mask;
-        mKeyBindings[mode][index].mFunction = function;
-
-        if (index == mKeyBindingCount[mode])
-            mKeyBindingCount[mode]++;
-    }
-
-	return TRUE;
-}
-
-BOOL LLViewerKeyboard::bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const bool ignore, const std::string& function_name)
-{
-    S32 index;
-    typedef boost::function<bool(EKeystate)> function_t;
-    function_t function = NULL;
-
-    function_t* result = LLKeyboardActionRegistry::getValue(function_name);
-    if (result)
-    {
-        function = *result;
-    }
-
-    if (!function)
-    {
-        LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
-        return FALSE;
-    }
-
-    // check for duplicate first and overwrite
-    if (ignore)
-    {
-        for (index = 0; index < mMouseIgnoreMaskCount[mode]; index++)
-        {
-            if (mouse == mMouseIgnoreMask[mode][index].mMouse)
-                break;
-        }
-    }
-    else
-    {
-        for (index = 0; index < mMouseBindingCount[mode]; index++)
-        {
-            if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask)
-                break;
-        }
-    }
-
-    if (index >= MAX_KEY_BINDINGS)
-    {
-        LL_ERRS() << "LLKeyboard::bindKey() - too many keys for mode " << mode << LL_ENDL;
-        return FALSE;
-    }
-
-    if (mode >= MODE_COUNT)
-    {
-        LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
-        return FALSE;
-    }
-
-    if (ignore)
-    {
-        mMouseIgnoreMask[mode][index].mMouse = mouse;
-        mMouseIgnoreMask[mode][index].mFunction = function;
-
-        if (index == mMouseIgnoreMaskCount[mode])
-            mMouseIgnoreMaskCount[mode]++;
-    }
-    else
-    {
-        mMouseBindings[mode][index].mMouse = mouse;
-        mMouseBindings[mode][index].mMask = mask;
-        mMouseBindings[mode][index].mFunction = function;
-
-        if (index == mMouseBindingCount[mode])
-            mMouseBindingCount[mode]++;
-    }
-
-    return TRUE;
-}
-
-LLViewerKeyboard::KeyBinding::KeyBinding()
-:	key("key"),
-	mouse("mouse"),
-	mask("mask"),
-	command("command"),
-	ignore("ignore", false)
-{}
-
-LLViewerKeyboard::KeyMode::KeyMode()
-:	bindings("binding")
-{}
-
-LLViewerKeyboard::Keys::Keys()
-:	first_person("first_person"),
-	third_person("third_person"),
-	edit("edit"),
-	sitting("sitting"),
-	edit_avatar("edit_avatar")
-{}
-
-void LLViewerKeyboard::resetBindings()
-{
-    for (S32 i = 0; i < MODE_COUNT; i++)
-    {
-        mKeyBindingCount[i] = 0;
-        mKeyIgnoreMaskCount[i] = 0;
-        mMouseBindingCount[i] = 0;
-        mMouseIgnoreMaskCount[i] = 0;
-    }
-}
-
-S32 LLViewerKeyboard::loadBindingsXML(const std::string& filename)
-{
-    resetBindings();
-
-	S32 binding_count = 0;
-	Keys keys;
-	LLSimpleXUIParser parser;
-
-	if (parser.readXUI(filename, keys) 
-		&& keys.validateBlock())
-	{
-		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 mode)
-{
-	S32 binding_count = 0;
-	for (LLInitParam::ParamIterator<KeyBinding>::const_iterator it = keymode.bindings.begin(), 
-			end_it = keymode.bindings.end();
-		it != end_it;
-		++it)
-	{
-        bool processed = false;
-        if (!it->key.getValue().empty())
-        {
-            KEY key;
-            LLKeyboard::keyFromString(it->key, &key);
-            if (key != KEY_NONE)
-            {
-                MASK mask;
-                bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;
-                LLKeyboard::maskFromString(it->mask, &mask);
-                bindKey(mode, key, mask, ignore, it->command);
-                processed = true;
-            }
-            else
-            {
-                LL_WARNS_ONCE() << "There might be issues in keybindings' file" << LL_ENDL;
-            }
-        }
-        if (!processed && it->mouse.isProvided() && !it->mouse.getValue().empty())
-        {
-            EMouseClickType mouse;
-            mouseFromString(it->mouse.getValue(), &mouse);
-            if (mouse != CLICK_NONE)
-            {
-                MASK mask;
-                bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;
-                LLKeyboard::maskFromString(it->mask, &mask);
-                bindMouse(mode, mouse, mask, ignore, it->command);
-                processed = true;
-            }
-            else
-            {
-                LL_WARNS_ONCE() << "There might be issues in keybindings' file" << LL_ENDL;
-            }
-        }
-        if (processed)
-        {
-            // total
-            binding_count++;
-        }
-	}
-
-	return binding_count;
-}
-
-EKeyboardMode LLViewerKeyboard::getMode() const
-{
-	if ( gAgentCamera.cameraMouselook() )
-	{
-		return MODE_FIRST_PERSON;
-	}
-	else if ( gMorphView && gMorphView->getVisible())
-	{
-		return MODE_EDIT_AVATAR;
-	}
-	else if (isAgentAvatarValid() && gAgentAvatarp->isSitting())
-	{
-		return MODE_SITTING;
-	}
-	else
-	{
-		return MODE_THIRD_PERSON;
-	}
-}
-
-bool LLViewerKeyboard::scanKey(const LLKeyboardBinding* binding,
-                               S32 binding_count,
-                               KEY key,
-                               MASK mask,
-                               BOOL key_down,
-                               BOOL key_up,
-                               BOOL key_level,
-                               bool repeat) const
-{
-	for (S32 i = 0; i < binding_count; i++)
-	{
-		if (binding[i].mKey == key)
-		{
-			if (binding[i].mMask == mask)
-			{
-				bool res = false;
-				if (key_down && !repeat)
-				{
-					// ...key went down this frame, call function
-					res = binding[i].mFunction( KEYSTATE_DOWN );
-					return true;
-				}
-				else if (key_up)
-				{
-					// ...key went down this frame, call function
-					res = binding[i].mFunction( KEYSTATE_UP );
-				}
-				else if (key_level)
-				{
-					// ...key held down from previous frame
-					// Not windows, just call the function.
-					res = binding[i].mFunction( KEYSTATE_LEVEL );
-				}//if
-				// Key+Mask combinations are supposed to be unique, so we won't find anything else
-				return res;
-			}//if
-		}//if
-	}//for
-	return false;
-}
-
-// Called from scanKeyboard.
-bool LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) const
-{
-	if (LLApp::isExiting())
-	{
-		return;
-	}
-
-	S32 mode = getMode();
-	// Consider keyboard scanning as NOT mouse event. JC
-	MASK mask = gKeyboard->currentMask(FALSE);
-
-	if (mKeyHandledByUI[key])
-	{
-		return false;
-	}
-
-	// don't process key down on repeated keys
-	BOOL repeat = gKeyboard->getKeyRepeated(key);
-
-    bool res = scanKey(mKeyBindings[mode], mKeyBindingCount[mode], key, mask, key_down, key_up, key_level, repeat);
-    if (!res)
-    {
-        // Nothing found, try ignore list
-        res = scanKey(mKeyIgnoreMask[mode], mKeyIgnoreMaskCount[mode], key, MASK_NONE, key_down, key_up, key_level, repeat);
-    }
-
-    if (!res && agent_control_lbutton.canHandle(CLICK_NONE, key, mask))
-    {
-        if (key_down && !repeat)
-        {
-            res = agen_control_lbutton_handle(KEYSTATE_DOWN);
-        }
-        if (key_up)
-        {
-            res = agen_control_lbutton_handle(KEYSTATE_UP);
-        }
-    }
-    return res;
-}
-
-BOOL LLViewerKeyboard::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down)
-{
-    BOOL handled = gViewerWindow->handleAnyMouseClick(window_impl, pos, mask, clicktype, down);
-
-    if (clicktype != CLICK_NONE)
-    {
-        // Special case
-        // If UI doesn't handle double click, LMB click is issued, so supres LMB 'down' when doubleclick is set
-        // handle !down as if we are handling doubleclick
-
-        bool double_click_sp = (clicktype == CLICK_LEFT
-            && (mMouseLevel[CLICK_DOUBLELEFT] != MOUSE_STATE_SILENT)
-            && mMouseLevel[CLICK_LEFT] == MOUSE_STATE_SILENT);
-        if (double_click_sp && !down)
-        {
-            // Process doubleclick instead
-            clicktype = CLICK_DOUBLELEFT;
-        }
-
-
-        if (double_click_sp && down)
-        {
-            // Consume click.
-            // Due to handling, double click that is not handled will be immediately followed by LMB click
-        }
-        // If UI handled 'down', it should handle 'up' as well
-        // If we handle 'down' not by UI, then we should handle 'up'/'level' regardless of UI
-        else if (handled)
-        {
-            // UI handled new 'down' so iterupt whatever state we were in.
-            if (mMouseLevel[clicktype] != MOUSE_STATE_SILENT)
-            {
-                if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN)
-                {
-                    mMouseLevel[clicktype] = MOUSE_STATE_CLICK;
-                }
-                else
-                {
-                    mMouseLevel[clicktype] = MOUSE_STATE_UP;
-                }
-            }
-        }
-        else if (down)
-        {
-            if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN)
-            {
-                // this is repeated hit (mouse does not repeat event until release)
-                // for now treat rapid clicking like mouse being held
-                mMouseLevel[clicktype] = MOUSE_STATE_LEVEL;
-            }
-            else
-            {
-                mMouseLevel[clicktype] = MOUSE_STATE_DOWN;
-            }
-        }
-        else if (mMouseLevel[clicktype] != MOUSE_STATE_SILENT)
-        {
-            // Released mouse key
-            if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN)
-            {
-                mMouseLevel[clicktype] = MOUSE_STATE_CLICK;
-            }
-            else 
-            {
-                mMouseLevel[clicktype] = MOUSE_STATE_UP;
-            }
-        }
-    }
-
-    return handled;
-}
-
-bool LLViewerKeyboard::scanMouse(const LLMouseBinding *binding, S32 binding_count, EMouseClickType mouse, MASK mask, EMouseState state) const
-{
-    for (S32 i = 0; i < binding_count; i++)
-    {
-        if (binding[i].mMouse == mouse && binding[i].mMask == mask)
-        {
-            bool res = false;
-            switch (state)
-            {
-            case MOUSE_STATE_DOWN:
-                res = binding[i].mFunction(KEYSTATE_DOWN);
-                break;
-            case MOUSE_STATE_CLICK:
-                // Button went down and up in scope of single frame
-                // might not work best with some functions,
-                // but some function need specific states specifically
-                res = binding[i].mFunction(KEYSTATE_DOWN);
-                res |= binding[i].mFunction(KEYSTATE_UP);
-                break;
-            case MOUSE_STATE_LEVEL:
-                res = binding[i].mFunction(KEYSTATE_LEVEL);
-                break;
-            case MOUSE_STATE_UP:
-                res = binding[i].mFunction(KEYSTATE_UP);
-                break;
-            default:
-                break;
-            }
-            // Key+Mask combinations are supposed to be unique, no need to continue
-            return res;
-        }
-    }
-    return false;
-}
-
-// todo: this recods key, scanMouse() triggers functions with EKeystate
-bool LLViewerKeyboard::scanMouse(EMouseClickType click, EMouseState state) const
-{
-    bool res = false;
-    S32 mode = getMode();
-    MASK mask = gKeyboard->currentMask(TRUE);
-    res = scanMouse(mMouseBindings[mode], mMouseBindingCount[mode], click, mask, state);
-    if (!res)
-    {
-        res = scanMouse(mMouseIgnoreMask[mode], mMouseIgnoreMaskCount[mode], click, MASK_NONE, state);
-    }
-    // no user defined actions found or those actions can't handle the key/button, handle control if nessesary
-    if (!res && agent_control_lbutton.canHandle(click, KEY_NONE, mask))
-    {
-        switch (state)
-        {
-        case MOUSE_STATE_DOWN:
-            agen_control_lbutton_handle(KEYSTATE_DOWN);
-            res = true;
-            break;
-        case MOUSE_STATE_CLICK:
-            // might not work best with some functions,
-            // but some function need specific states too specifically
-            agen_control_lbutton_handle(KEYSTATE_DOWN);
-            agen_control_lbutton_handle(KEYSTATE_UP);
-            res = true;
-            break;
-        case MOUSE_STATE_UP:
-            agen_control_lbutton_handle(KEYSTATE_UP);
-            res = true;
-            break;
-        default:
-            break;
-        }
-    }
-    return res;
-}
-
-void LLViewerKeyboard::scanMouse()
-{
-    for (S32 i = 0; i < CLICK_COUNT; i++)
-    {
-        if (mMouseLevel[i] != MOUSE_STATE_SILENT)
-        {
-            scanMouse((EMouseClickType)i, mMouseLevel[i]);
-            if (mMouseLevel[i] == MOUSE_STATE_DOWN)
-            {
-                // mouse doesn't support 'continued' state, so after handling, switch to LEVEL
-                mMouseLevel[i] = MOUSE_STATE_LEVEL;
-            }
-            else if (mMouseLevel[i] == MOUSE_STATE_UP || mMouseLevel[i] == MOUSE_STATE_CLICK)
-            {
-                mMouseLevel[i] = MOUSE_STATE_SILENT;
-            }
-        }
-    }
-}
diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h
deleted file mode 100644
index 02fa21d4f2..0000000000
--- a/indra/newview/llviewerkeyboard.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/** 
- * @file llviewerkeyboard.h
- * @brief LLViewerKeyboard class header file
- *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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_LLVIEWERKEYBOARD_H
-#define LL_LLVIEWERKEYBOARD_H
-
-#include "llkeyboard.h" // For EKeystate
-#include "llinitparam.h"
-
-const S32 MAX_NAMED_FUNCTIONS = 100;
-const S32 MAX_KEY_BINDINGS = 128; // was 60
-
-class LLNamedFunction
-{
-public:
-	LLNamedFunction() : mFunction(NULL) { };
-	~LLNamedFunction() { };
-
-	std::string	mName;
-	LLKeyFunc	mFunction;
-};
-
-class LLKeyboardBinding
-{
-public:
-    KEY				mKey;
-    MASK			mMask;
-    bool			mIgnoreMask; // whether CTRL/ALT/SHIFT should be checked
-
-    LLKeyFunc		mFunction;
-};
-
-class LLMouseBinding
-{
-public:
-    EMouseClickType	mMouse;
-    MASK			mMask;
-    bool			mIgnoreMask; // whether CTRL/ALT/SHIFT should be checked
-
-    LLKeyFunc		mFunction;
-};
-
-
-typedef enum e_keyboard_mode
-{
-	MODE_FIRST_PERSON,
-	MODE_THIRD_PERSON,
-	MODE_EDIT,
-	MODE_EDIT_AVATAR,
-	MODE_SITTING,
-	MODE_COUNT
-} EKeyboardMode;
-
-class LLWindow;
-
-void bind_keyboard_functions();
-
-class LLViewerKeyboard
-{
-public:
-	struct KeyBinding : public LLInitParam::Block<KeyBinding>
-	{
-		Mandatory<std::string>	key,
-								mask,
-								command;
-		Optional<std::string>	mouse; // Note, not mandatory for the sake of backward campatibility
-		Optional<bool>			ignore;
-
-		KeyBinding();
-	};
-
-	struct KeyMode : public LLInitParam::Block<KeyMode>
-	{
-		Multiple<KeyBinding>		bindings;
-
-		KeyMode();
-	};
-
-	struct Keys : public LLInitParam::Block<Keys>
-	{
-		Optional<KeyMode>	first_person,
-							third_person,
-							edit,
-							sitting,
-							edit_avatar;
-
-		Keys();
-	};
-
-	LLViewerKeyboard();
-
-	BOOL			handleKey(KEY key, MASK mask, BOOL repeated);
-	BOOL			handleKeyUp(KEY key, MASK mask);
-
-	S32				loadBindingsXML(const std::string& filename);										// returns number bound, 0 on error
-	EKeyboardMode	getMode() const;
-
-	BOOL			modeFromString(const std::string& string, S32 *mode) const;			// False on failure
-	BOOL			mouseFromString(const std::string& string, EMouseClickType *mode) const;// False on failure
-
-    bool            scanKey(KEY key,
-                            BOOL key_down,
-                            BOOL key_up,
-                            BOOL key_level) const;
-
-    // handleMouse() records state, scanMouse() goes through states, scanMouse(click) processes individual saved states after UI is done with them
-    BOOL			handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down);
-	void LLViewerKeyboard::scanMouse();
-
-private:
-    bool            scanKey(const LLKeyboardBinding* binding,
-                            S32 binding_count,
-                            KEY key,
-                            MASK mask,
-                            BOOL key_down,
-                            BOOL key_up,
-                            BOOL key_level,
-                            bool repeat) const;
-
-    enum EMouseState
-    {
-        MOUSE_STATE_DOWN, // key down this frame
-        MOUSE_STATE_CLICK, // key went up and down in scope of same frame
-        MOUSE_STATE_LEVEL, // clicked again fast, or never released
-        MOUSE_STATE_UP, // went up this frame
-        MOUSE_STATE_SILENT // notified about 'up', do not notify again
-    };
-    bool			scanMouse(EMouseClickType click, EMouseState state) const;
-    bool            scanMouse(const LLMouseBinding *binding,
-                          S32 binding_count,
-                          EMouseClickType mouse,
-                          MASK mask,
-                          EMouseState state) const;
-
-    S32				loadBindingMode(const LLViewerKeyboard::KeyMode& keymode, S32 mode);
-    BOOL			bindKey(const S32 mode, const KEY key, const MASK mask, const bool ignore, const std::string& function_name);
-    BOOL			bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const bool ignore, const std::string& function_name);
-    void			resetBindings();
-
-	// Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here
-    // We process specific keys first, then keys that should ignore mask.
-    // This way with W+ignore defined to 'forward' and with ctrl+W tied to camera,
-    // pressing undefined Shift+W will do 'forward', yet ctrl+W will do 'camera forward'
-    // With A defined to 'turn', shift+A defined to strafe, pressing Shift+W+A will do strafe+forward
-
-    // TODO: at some point it is better to remake this, especially keyaboard part
-    // would be much better to send to functions actual state of the button than
-    // to send what we think function wants based on collection of bools (mKeyRepeated, mKeyLevel, mKeyDown)
-    S32				mKeyBindingCount[MODE_COUNT];
-    S32				mKeyIgnoreMaskCount[MODE_COUNT];
-    S32				mMouseBindingCount[MODE_COUNT];
-    S32				mMouseIgnoreMaskCount[MODE_COUNT];
-    LLKeyboardBinding	mKeyBindings[MODE_COUNT][MAX_KEY_BINDINGS];
-    LLKeyboardBinding	mKeyIgnoreMask[MODE_COUNT][MAX_KEY_BINDINGS];
-    LLMouseBinding		mMouseBindings[MODE_COUNT][MAX_KEY_BINDINGS];
-    LLMouseBinding		mMouseIgnoreMask[MODE_COUNT][MAX_KEY_BINDINGS];
-
-	typedef std::map<U32, U32> key_remap_t;
-	key_remap_t		mRemapKeys[MODE_COUNT];
-	std::set<KEY>	mKeysSkippedByUI;
-	BOOL			mKeyHandledByUI[KEY_COUNT];		// key processed successfully by UI
-
-    // This is indentical to what llkeyboard does (mKeyRepeated, mKeyLevel, mKeyDown e t c),
-    // just instead of remembering individually as bools,  we record state as enum
-    EMouseState		mMouseLevel[CLICK_COUNT];	// records of key state
-};
-
-extern LLViewerKeyboard gViewerKeyboard;
-
-#endif // LL_LLVIEWERKEYBOARD_H
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index caf7a8a65a..5388d13a04 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -45,7 +45,7 @@
 #include "llmeshrepository.h"
 #include "llnotificationhandler.h"
 #include "llpanellogin.h"
-#include "llviewerkeyboard.h"
+#include "llviewerinput.h"
 #include "llviewermenu.h"
 
 #include "llviewquery.h"
@@ -173,7 +173,7 @@
 #include "llviewergesture.h"
 #include "llviewertexturelist.h"
 #include "llviewerinventory.h"
-#include "llviewerkeyboard.h"
+#include "llviewerinput.h"
 #include "llviewermedia.h"
 #include "llviewermediafocus.h"
 #include "llviewermenu.h"
@@ -1081,7 +1081,7 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask
     }    
     BOOL down = TRUE;
     //handleMouse() loops back to LLViewerWindow::handleAnyMouseClick
-    return gViewerKeyboard.handleMouse(window, pos, mask, CLICK_LEFT, down);
+    return gViewerInput.handleMouse(window, pos, mask, CLICK_LEFT, down);
 }
 
 BOOL LLViewerWindow::handleDoubleClick(LLWindow *window,  LLCoordGL pos, MASK mask)
@@ -1089,7 +1089,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 (gViewerKeyboard.handleMouse(window, pos, mask, CLICK_DOUBLELEFT, down))
+	if (gViewerInput.handleMouse(window, pos, mask, CLICK_DOUBLELEFT, down))
 	{
 		return TRUE;
 	}
@@ -1103,24 +1103,24 @@ BOOL LLViewerWindow::handleMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)
         mMouseDownTimer.stop();
     }
     BOOL down = FALSE;
-    return gViewerKeyboard.handleMouse(window, pos, mask, CLICK_LEFT, down);
+    return gViewerInput.handleMouse(window, pos, mask, CLICK_LEFT, down);
 }
 BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask)
 {
 	BOOL down = TRUE;
-	return gViewerKeyboard.handleMouse(window, pos, mask, CLICK_RIGHT, down);
+	return gViewerInput.handleMouse(window, pos, mask, CLICK_RIGHT, down);
 }
 
 BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)
 {
 	BOOL down = FALSE;
- 	return gViewerKeyboard.handleMouse(window, pos, mask, CLICK_RIGHT, down);
+ 	return gViewerInput.handleMouse(window, pos, mask, CLICK_RIGHT, down);
 }
 
 BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask)
 {
 	BOOL down = TRUE;
- 	gViewerKeyboard.handleMouse(window, pos, mask, CLICK_MIDDLE, down);
+ 	gViewerInput.handleMouse(window, pos, mask, CLICK_MIDDLE, down);
   
   	// Always handled as far as the OS is concerned.
 	return TRUE;
@@ -1275,7 +1275,7 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi
 BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)
 {
 	BOOL down = FALSE;
- 	gViewerKeyboard.handleMouse(window, pos, mask, CLICK_MIDDLE, down);
+ 	gViewerInput.handleMouse(window, pos, mask, CLICK_MIDDLE, down);
   
   	// Always handled as far as the OS is concerned.
 	return TRUE;
@@ -1286,10 +1286,10 @@ BOOL LLViewerWindow::handleOtherMouse(LLWindow *window, LLCoordGL pos, MASK mask
     switch (button)
     {
     case 4:
-        gViewerKeyboard.handleMouse(window, pos, mask, CLICK_BUTTON4, down);
+        gViewerInput.handleMouse(window, pos, mask, CLICK_BUTTON4, down);
         break;
     case 5:
-        gViewerKeyboard.handleMouse(window, pos, mask, CLICK_BUTTON5, down);
+        gViewerInput.handleMouse(window, pos, mask, CLICK_BUTTON5, down);
         break;
     default:
         break;
@@ -1454,7 +1454,7 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key,  MASK mask, BOOL repeated)
 	}
 
     // remaps, handles ignored cases and returns back to viewer window.
-    return gViewerKeyboard.handleKey(key, mask, repeated);
+    return gViewerInput.handleKey(key, mask, repeated);
 }
 
 BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key,  MASK mask)
@@ -1466,13 +1466,13 @@ BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key,  MASK mask)
 		tool_inspectp->keyUp(key, mask);
 	}
 
-	return gViewerKeyboard.handleKeyUp(key, mask);
+	return gViewerInput.handleKeyUp(key, mask);
 }
 
 void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
 {
 	LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true);
-	gViewerKeyboard.scanKey(key, key_down, key_up, key_level);
+	gViewerInput.scanKey(key, key_down, key_up, key_level);
 	return; // Be clear this function returns nothing
 }
 
@@ -2930,7 +2930,7 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
 		if (mask != MASK_ALT)
 		{
 			// remaps, handles ignored cases and returns back to viewer window.
-			return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
+			return gViewerInput.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
 		}
 	}
 
diff --git a/indra/newview/llwindowlistener.cpp b/indra/newview/llwindowlistener.cpp
index 5367262bb6..2c6905f4b0 100644
--- a/indra/newview/llwindowlistener.cpp
+++ b/indra/newview/llwindowlistener.cpp
@@ -37,7 +37,7 @@
 #include "llview.h"
 #include "llviewinject.h"
 #include "llviewerwindow.h"
-#include "llviewerkeyboard.h"
+#include "llviewerinput.h"
 #include "llrootview.h"
 #include "llsdutil.h"
 #include "stringize.h"
@@ -279,7 +279,7 @@ void LLWindowListener::keyDown(LLSD const & evt)
 			response.setResponse(target_view->getInfo());
 			
 			gFocusMgr.setKeyboardFocus(target_view);
-			gViewerKeyboard.handleKey(key, mask, false);
+			gViewerInput.handleKey(key, mask, false);
 			if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
 		}
 		else 
@@ -291,7 +291,7 @@ void LLWindowListener::keyDown(LLSD const & evt)
 	}
 	else 
 	{
-		gViewerKeyboard.handleKey(key, mask, false); 
+		gViewerInput.handleKey(key, mask, false); 
 		if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
 	}
 }
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
index ac4be34be2..62267dce8a 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
@@ -285,7 +285,7 @@
    width="110"
    label="Restore Default"
    name="restore_defaults"/>
-  
+
   <scroll_list
    draw_heading="true"
    follows="all"
@@ -315,8 +315,5 @@
      relative_width="0.22"
      label="Control Method 3"
      name="lst_ctrl3" />
-    <scroll_list.commit_callback
-      function="Pref.CommitControl" />
   </scroll_list>
-
 </panel>
-- 
cgit v1.2.3


From a8e56e67c3545cf857f80e81b3e98a278224f421 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Fri, 27 Sep 2019 19:53:33 +0300
Subject: SL-6109 Cleanup, run commands, and preparation for tooltip support

---
 indra/newview/llfloaterpreference.cpp              | 369 +++++++++++-------
 indra/newview/llfloaterpreference.h                |   4 +-
 indra/newview/llkeyconflict.cpp                    | 426 ++++++++-------------
 indra/newview/llkeyconflict.h                      | 117 +-----
 indra/newview/llviewerinput.cpp                    |  76 ++++
 indra/newview/llviewerwindow.cpp                   |   2 +
 .../default/xui/en/panel_preferences_controls.xml  |  55 +--
 7 files changed, 510 insertions(+), 539 deletions(-)

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index c0e334795a..088a0820aa 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -185,18 +185,53 @@ public:
 	static void onCancel(void* user_data);
 	static void onBlank(void* user_data);
 	static void onDefault(void* user_data);
+	static void onClickTimeout(void* user_data, MASK mask);
+
+	class Updater;
 
 private:
+	void setKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore);
 	LLPanelPreferenceControls* pParent;
 	LLCheckBoxCtrl* pCheckBox;
 
-	U32 mKeyMask;
+	U32 mKeyFilterMask;
+	Updater *pUpdater;
+};
+
+class LLSetKeyBindDialog::Updater : public LLEventTimer
+{
+public:
+
+    typedef boost::function<void(MASK)> callback_t;
+
+    Updater(callback_t cb, F32 period, MASK mask)
+        :LLEventTimer(period),
+        mMask(mask),
+        mCallback(cb)
+    {
+        mEventTimer.start();
+    }
+
+    virtual ~Updater(){}
+
+protected:
+    BOOL tick()
+    {
+        mCallback(mMask);
+        // Deletes itseft after execution
+        return TRUE;
+    }
+
+private:
+    MASK mMask;
+    callback_t mCallback;
 };
 
 LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key)
   : LLModalDialog(key),
 	pParent(NULL),
-	mKeyMask(DEFAULT_KEY_FILTER)
+	mKeyFilterMask(DEFAULT_KEY_FILTER),
+	pUpdater(NULL)
 {
 }
 
@@ -227,13 +262,19 @@ void LLSetKeyBindDialog::onClose(bool app_quiting)
         pParent->onCancelKeyBind();
         pParent = NULL;
     }
+    if (pUpdater)
+    {
+        // Doubleclick timer has't fired, delete it
+        delete pUpdater;
+        pUpdater = NULL;
+    }
     LLModalDialog::onClose(app_quiting);
 }
 
 void LLSetKeyBindDialog::setParent(LLPanelPreferenceControls* parent, U32 key_mask)
 {
     pParent = parent;
-    mKeyMask = key_mask;
+    mKeyFilterMask = key_mask;
 
     LLTextBase *text_ctrl = getChild<LLTextBase>("descritption");
 
@@ -259,24 +300,18 @@ void LLSetKeyBindDialog::setParent(LLPanelPreferenceControls* parent, U32 key_ma
 
 BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
 {
-	BOOL result = TRUE;
-
     if ((key == 'Q' && mask == MASK_CONTROL)
         || key == KEY_ESCAPE)
     {
         closeFloater();
-        return true;
+        return TRUE;
     }
 
     if (key == KEY_DELETE)
     {
-        if (pParent)
-        {
-            pParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
-            pParent = NULL;
-        }
+        setKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
         closeFloater();
-        return true;
+        return FALSE;
     }
 
     // forbidden keys
@@ -284,40 +319,41 @@ BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
         || key == KEY_RETURN
         || key == KEY_BACKSPACE)
     {
-        return false;
+        return FALSE;
     }
 
-    if ((mKeyMask & ALLOW_MASKS) == 0
+    if ((mKeyFilterMask & ALLOW_MASKS) == 0
         && (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT))
     {
         // mask by themself are not allowed
-        return false;
+        return FALSE;
     }
-    else if ((mKeyMask & ALLOW_KEYS) == 0)
+    else if ((mKeyFilterMask & ALLOW_KEYS) == 0)
     {
         // basic keys not allowed
-        return false;
+        return FALSE;
     }
-    else if ((mKeyMask & ALLOW_MASK_KEYS) == 0 && mask != 0)
+    else if ((mKeyFilterMask & ALLOW_MASK_KEYS) == 0 && mask != 0)
     {
         // masked keys not allowed
-        return false;
+        return FALSE;
     }
 
-	if (pParent)
-	{
-        pParent->onSetKeyBind(CLICK_NONE, key, mask, pCheckBox->getValue().asBoolean());
-        pParent = NULL;
-	}
-	closeFloater();
-	return result;
+    setKeyBind(CLICK_NONE, key, mask, pCheckBox->getValue().asBoolean());
+    closeFloater();
+    return TRUE;
 }
 
 BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down)
 {
     BOOL result = FALSE;
-
-    if (clicktype == CLICK_LEFT)
+    if (!pParent)
+    {
+        // we already processed 'down' event, this is 'up', consume
+        closeFloater();
+        result = TRUE;
+    }
+    if (!result && clicktype == CLICK_LEFT)
     {
         // try handling buttons first
         if (down)
@@ -328,25 +364,38 @@ BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClic
         {
             result = LLView::handleMouseUp(x, y, mask);
         }
+        if (result)
+        {
+            setFocus(TRUE);
+            gFocusMgr.setKeystrokesOnly(TRUE);
+        }
+        // ignore selection related combinations
+        else if (down && (mask & (MASK_SHIFT | MASK_CONTROL)) == 0)
+        {
+            // this can be a double click, wait a bit;
+            if (!pUpdater)
+            {
+                // Note: default doubleclick time is 500ms, but can stretch up to 5s
+                pUpdater = new Updater(boost::bind(&onClickTimeout, this, _1), 0.7f, mask);
+                result = TRUE;
+            }
+        }
     }
 
     if (!result
-        && ((mKeyMask & ALLOW_MOUSE) != 0)
+        && (clicktype != CLICK_LEFT) // subcases were handled above
+        && ((mKeyFilterMask & ALLOW_MOUSE) != 0)
         && (clicktype != CLICK_RIGHT || mask != 0) // reassigning menu button is not supported
-        && ((mKeyMask & ALLOW_MASK_MOUSE) != 0 || mask == 0))
+        && ((mKeyFilterMask & ALLOW_MASK_MOUSE) != 0 || mask == 0)) // reserved for selection
     {
-        if (pParent)
+        setKeyBind(clicktype, KEY_NONE, mask, pCheckBox->getValue().asBoolean());
+        result = TRUE;
+        if (!down)
         {
-            pParent->onSetKeyBind(clicktype, KEY_NONE, mask, pCheckBox->getValue().asBoolean());
-            pParent = NULL;
+            // wait for 'up' event before closing
+            // alternative: set pUpdater
+            closeFloater();
         }
-        result = TRUE;
-        closeFloater();
-    }
-    
-    if (!result)
-    {
-        result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down);
     }
 
     return result;
@@ -356,7 +405,7 @@ BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClic
 void LLSetKeyBindDialog::onCancel(void* user_data)
 {
     LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
-	self->closeFloater();
+    self->closeFloater();
 }
 
 //static
@@ -364,11 +413,7 @@ void LLSetKeyBindDialog::onBlank(void* user_data)
 {
     LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
     // tmp needs 'no key' button
-    if (self->pParent)
-    {
-        self->pParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
-        self->pParent = NULL;
-    }
+    self->setKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
     self->closeFloater();
 }
 
@@ -376,7 +421,6 @@ void LLSetKeyBindDialog::onBlank(void* user_data)
 void LLSetKeyBindDialog::onDefault(void* user_data)
 {
     LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
-    // tmp needs 'no key' button
     if (self->pParent)
     {
         self->pParent->onDefaultKeyBind();
@@ -385,6 +429,27 @@ void LLSetKeyBindDialog::onDefault(void* user_data)
     self->closeFloater();
 }
 
+//static
+void LLSetKeyBindDialog::onClickTimeout(void* user_data, MASK mask)
+{
+    LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
+
+    // timer will delete itself after timeout
+    self->pUpdater = NULL;
+
+    self->setKeyBind(CLICK_LEFT, KEY_NONE, mask, self->pCheckBox->getValue().asBoolean());
+    self->closeFloater();
+}
+
+void LLSetKeyBindDialog::setKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore)
+{
+    if (pParent)
+    {
+        pParent->onSetKeyBind(click, key, mask, ignore);
+        pParent = NULL;
+    }
+}
+
 
 // global functions 
 
@@ -2972,9 +3037,72 @@ void LLPanelPreferenceGraphics::setHardwareDefaults()
 //------------------------LLPanelPreferenceControls--------------------------------
 static LLPanelInjector<LLPanelPreferenceControls> t_pref_contrls("panel_preference_controls");
 
+//name of control and name of icon if it is a group, likely 'TEMP' until xml gets properly populated
+typedef std::vector<std::pair<std::string, std::string> > controls_to_icon_t;
+static const controls_to_icon_t commands_and_headers =
+{
+    //{ "control_view_actions", "Search_Icon" },
+    //{ "control_interactions", "Command_Gestures_Icon" },
+    { "control_movements", "Move_Walk_Off" },
+    { "walk_to", "" },
+    { "teleport_to", "" },
+    { "push_forward", "" },
+    { "push_backward", "" },
+    { "turn_left", "" },
+    { "turn_right", "" },
+    { "slide_left", "" },
+    { "slide_right", "" },
+    { "jump", "" },
+    { "push_down", "" },
+    { "run_forward", "" },
+    { "run_backward", "" },
+    { "run_left", "" },
+    { "run_right", "" },
+    { "toggle_run", "" },
+    { "toggle_fly", "" },
+    { "toggle_sit", "" },
+    { "stop_moving", "" },
+    { "control_camera", "Cam_FreeCam_Off" },
+    { "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", "Tool_Dozer" },
+    { "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", "Audio_Press" },
+    { "toggle_pause_media", "" },
+    { "toggle_enable_media", "" },
+    { "voice_follow_key", "" },
+    { "toggle_voice", "" },
+    { "start_chat", "" },
+    { "start_gesture", "" },
+};
+
 LLPanelPreferenceControls::LLPanelPreferenceControls()
     :LLPanelPreference(),
-    mEditingIndex(-1),
     mEditingColumn(-1),
     mEditingMode(0),
     mShowKeyDialog(false),
@@ -3013,8 +3141,8 @@ BOOL LLPanelPreferenceControls::handleHover(S32 x, S32 y, MASK mask)
     if (mShowKeyDialog)
     {
         mShowKeyDialog = false;
-        if (mEditingIndex > 0
-            && mConflictHandler[mEditingMode].canAssignControl((LLKeyConflictHandler::EControlTypes)mEditingIndex))
+        if (!mEditingControl.empty()
+            && mConflictHandler[mEditingMode].canAssignControl(mEditingControl))
         {
             LLScrollListItem* item = pControlsTable->getFirstSelected(); // don't use pControlsTable->hitItem(x, y) dur to drift;
             if (item)
@@ -3042,10 +3170,10 @@ BOOL LLPanelPreferenceControls::handleHover(S32 x, S32 y, MASK mask)
     return LLPanelPreference::handleHover(x, y, mask);
 }
 
-void LLPanelPreferenceControls::addGroupRow(const std::string &icon, S32 index)
+void LLPanelPreferenceControls::addGroupRow(const std::string &control_name, const std::string &icon)
 {
     LLScrollListItem::Params item_params;
-    item_params.value = LLSD::Integer(-1);
+    item_params.value = "";
 
     LLScrollListCell::Params icon_cell_params;
     icon_cell_params.font = LLFontGL::getFontSansSerif();
@@ -3057,7 +3185,6 @@ void LLPanelPreferenceControls::addGroupRow(const std::string &icon, S32 index)
     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))
     {
@@ -3110,76 +3237,48 @@ void LLPanelPreferenceControls::populateControlTable()
     cell_params.column = "";
     cell_params.value = label;
 
-    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++)
+    controls_to_icon_t::const_iterator iter = commands_and_headers.begin();
+    controls_to_icon_t::const_iterator end = commands_and_headers.end();
+    for (; iter != end; ++iter)
     {
-        LLKeyConflictHandler::EControlTypes type = (LLKeyConflictHandler::EControlTypes)i;
-        switch (type)
+        if (iter->second.empty())
         {
-        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:
+            // general control
+            LLScrollListItem::Params item_params;
+            item_params.value = LLSD(iter->first);
+
+            cell_params.column = "lst_action";
+            bool enabled = mConflictHandler[mEditingMode].canAssignControl(iter->first);
+            if (hasString(iter->first))
             {
-                //default insert
-                LLScrollListItem::Params item_params;
-                item_params.value = LLSD::Integer(i);
-
-                cell_params.column = "lst_action";
-                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 = mConflictHandler[mEditingMode].getControlString(type, 0);
-                cell_params.enabled = enabled;
-                item_params.columns.add(cell_params);
-                cell_params.column = "lst_ctrl2";
-                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);
-                break;
+                label = getString(iter->first);
             }
+            else
+            {
+                label = iter->first;
+            }
+            cell_params.value = label;
+            item_params.columns.add(cell_params);
+            cell_params.column = "lst_ctrl1";
+            cell_params.value = mConflictHandler[mEditingMode].getControlString(iter->first, 0);
+            cell_params.enabled = enabled;
+            item_params.columns.add(cell_params);
+            cell_params.column = "lst_ctrl2";
+            cell_params.value = mConflictHandler[mEditingMode].getControlString(iter->first, 1);
+            cell_params.enabled = enabled;
+            item_params.columns.add(cell_params);
+            cell_params.column = "lst_ctrl3";
+            cell_params.value = mConflictHandler[mEditingMode].getControlString(iter->first, 2);
+            cell_params.enabled = enabled;
+            item_params.columns.add(cell_params);
+
+            pControlsTable->addRow(item_params, EAddPosition::ADD_BOTTOM);
+        }
+        else
+        {
+            // header
+            addSeparator();
+            addGroupRow(iter->first, iter->second);
         }
     }
 }
@@ -3195,13 +3294,13 @@ void LLPanelPreferenceControls::addSeparator()
 
 void LLPanelPreferenceControls::updateTable()
 {
+    mEditingControl.clear();
     std::vector<LLScrollListItem*> list = pControlsTable->getAllData();
     for (S32 i = 0; i < list.size(); ++i)
     {
-        S32 value = list[i]->getValue().asInteger();
-        if (value > 0)
+        std::string control = list[i]->getValue();
+        if (!control.empty())
         {
-            LLKeyConflictHandler::EControlTypes control = (LLKeyConflictHandler::EControlTypes)value;
             LLScrollListCell* cell = list[i]->getColumn(1);
             cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 0));
             cell = list[i]->getColumn(2);
@@ -3258,6 +3357,7 @@ void LLPanelPreferenceControls::saveSettings()
         if (mConflictHandler[i].hasUnsavedChanges())
         {
             mConflictHandler[i].saveToSettings();
+            mConflictHandler[i].clear();
         }
     }
 
@@ -3280,20 +3380,21 @@ void LLPanelPreferenceControls::resetDirtyChilds()
 
 void LLPanelPreferenceControls::onListCommit()
 {
+    mShowKeyDialog = false;
     LLScrollListItem* item = pControlsTable->getFirstSelected();
     if (item == NULL)
     {
         return;
     }
 
-    S32 control = item->getValue().asInteger();
+    std::string control = item->getValue();
 
-    if (control <= 0)
+    if (control.empty())
     {
         return;
     }
 
-    if (!mConflictHandler[mEditingMode].canAssignControl((LLKeyConflictHandler::EControlTypes)control))
+    if (!mConflictHandler[mEditingMode].canAssignControl(control))
     {
         return;
     }
@@ -3302,7 +3403,7 @@ void LLPanelPreferenceControls::onListCommit()
     // 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;
+    mEditingControl = control;
     mShowKeyDialog = true;
 
     if (mHighlightedCell)
@@ -3320,18 +3421,16 @@ void LLPanelPreferenceControls::onModeCommit()
 // todo: copy onSetKeyBind to interface and inherit from interface
 void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore_mask)
 {
-    LLKeyConflictHandler::EControlTypes control = (LLKeyConflictHandler::EControlTypes)mEditingIndex;
-
-    if (!mConflictHandler[mEditingMode].canAssignControl(control))
+    if (!mConflictHandler[mEditingMode].canAssignControl(mEditingControl))
     {
         return;
     }
 
     pControlsTable->deselectAllItems();
-    pControlsTable->selectByValue(mEditingIndex);
+    pControlsTable->selectByValue(mEditingControl);
     if ( mEditingColumn > 0)
     {
-        mConflictHandler[mEditingMode].registerControl(control, mEditingColumn - 1, click, key, mask, ignore_mask);
+        mConflictHandler[mEditingMode].registerControl(mEditingControl, mEditingColumn - 1, click, key, mask, ignore_mask);
     }
 
     updateTable();
@@ -3347,19 +3446,17 @@ void LLPanelPreferenceControls::onRestoreDefaults()
 
 void LLPanelPreferenceControls::onDefaultKeyBind()
 {
-    LLKeyConflictHandler::EControlTypes control = (LLKeyConflictHandler::EControlTypes)mEditingIndex;
-
-    if (!mConflictHandler[mEditingMode].canAssignControl(control))
+    if (!mConflictHandler[mEditingMode].canAssignControl(mEditingControl))
     {
         return;
     }
 
     pControlsTable->deselectAllItems();
-    pControlsTable->selectByValue(mEditingIndex);
+    pControlsTable->selectByValue(mEditingControl);
 
     if (mEditingColumn > 0)
     {
-        mConflictHandler[mEditingMode].resetToDefault(control, mEditingColumn - 1);
+        mConflictHandler[mEditingMode].resetToDefault(mEditingControl, mEditingColumn - 1);
     }
     updateTable();
 }
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 513fda96df..2fe3b98abd 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -317,7 +317,7 @@ public:
 	void onCancelKeyBind();
 
 private:
-	void addGroupRow(const std::string &icon, S32 index);
+	void addGroupRow(const std::string &control_name, const std::string &icon);
 	void regenerateControls();
 	void populateControlTable();
 	void addSeparator();
@@ -327,7 +327,7 @@ private:
 	LLComboBox *pKeyModeBox;
 	LLScrollListCell *mHighlightedCell;
 	LLKeyConflictHandler mConflictHandler[LLKeyConflictHandler::MODE_COUNT];
-	S32 mEditingIndex;
+	std::string mEditingControl;
 	S32 mEditingColumn;
 	S32 mEditingMode;
 	bool mShowKeyDialog;
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index e81d121e3b..c74eea6e47 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -41,135 +41,7 @@
 #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",
-    "walk_to",
-    "teleport_to",
-    "push_forward",
-    "push_backward",
-    "turn_left",
-    "turn_right",
-    "slide_left",
-    "slide_right",
-    "jump",
-    "push_down",
-    //"control_run",
-    "toggle_run",
-    "toggle_fly",
-    "toggle_sit",
-    "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",
-    "toggle_pause_media",
-    "toggle_enable_media",
-    "voice_follow_key",
-    "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 llviewerinput
-typedef std::map<std::string, LLKeyConflictHandler::EControlTypes> 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 },
-    { "toggle_run", LLKeyConflictHandler::CONTROL_TOGGLE_RUN },
-    { "toggle_sit", LLKeyConflictHandler::CONTROL_SIT },
-    { "toggle_parcel_media", LLKeyConflictHandler::CONTROL_PAUSE_MEDIA },
-    { "toggle_enable_media", LLKeyConflictHandler::CONTROL_ENABLE_MEDIA },
-    { "walk_to", LLKeyConflictHandler::CONTROL_MOVETO },
-    { "teleport_to", LLKeyConflictHandler::CONTROL_TELEPORTTO },
-    { "toggle_voice", LLKeyConflictHandler::CONTROL_TOGGLE_VOICE },
-    { "voice_follow_key", LLKeyConflictHandler::CONTROL_VOICE },
-};
+static const std::string saved_settings_key_controls[] = { "placeholder" };
 
 
 // LLKeyboard::stringFromMask is meant for UI and is OS dependent,
@@ -267,29 +139,29 @@ LLKeyConflictHandler::LLKeyConflictHandler(ESourceMode mode)
     loadFromSettings(mode);
 }
 
-bool LLKeyConflictHandler::canHandleControl(LLKeyConflictHandler::EControlTypes control_type, EMouseClickType mouse_ind, KEY key, MASK mask)
+bool LLKeyConflictHandler::canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask)
 {
-    return mControlsMap[control_type].canHandle(mouse_ind, key, mask);
+    return mControlsMap[control_name].canHandle(mouse_ind, key, mask);
 }
 
-bool LLKeyConflictHandler::canHandleKey(EControlTypes control_type, KEY key, MASK mask)
+bool LLKeyConflictHandler::canHandleKey(const std::string &control_name, KEY key, MASK mask)
 {
-    return canHandleControl(control_type, CLICK_NONE, key, mask);
+    return canHandleControl(control_name, CLICK_NONE, key, mask);
 }
 
-bool LLKeyConflictHandler::canHandleMouse(LLKeyConflictHandler::EControlTypes control_type, EMouseClickType mouse_ind, MASK mask)
+bool LLKeyConflictHandler::canHandleMouse(const std::string &control_name, EMouseClickType mouse_ind, MASK mask)
 {
-    return canHandleControl(control_type, mouse_ind, KEY_NONE, mask);
+    return canHandleControl(control_name, mouse_ind, KEY_NONE, mask);
 }
 
-bool LLKeyConflictHandler::canHandleMouse(EControlTypes control_type, S32 mouse_ind, MASK mask)
+bool LLKeyConflictHandler::canHandleMouse(const std::string &control_name, S32 mouse_ind, MASK mask)
 {
-    return canHandleControl(control_type, (EMouseClickType)mouse_ind, KEY_NONE, mask);
+    return canHandleControl(control_name, (EMouseClickType)mouse_ind, KEY_NONE, mask);
 }
 
-bool LLKeyConflictHandler::canAssignControl(EControlTypes control_type)
+bool LLKeyConflictHandler::canAssignControl(const std::string &control_name)
 {
-    std::map<EControlTypes, LLKeyConflict>::iterator iter = mControlsMap.find(control_type);
+    control_map_t::iterator iter = mControlsMap.find(control_name);
     if (iter != mControlsMap.end())
     {
         return iter->second.mAssignable;
@@ -297,9 +169,13 @@ bool LLKeyConflictHandler::canAssignControl(EControlTypes control_type)
     return false;
 }
 
-bool LLKeyConflictHandler::registerControl(EControlTypes control_type, U32 index, EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask)
+bool LLKeyConflictHandler::registerControl(const std::string &control_name, U32 index, EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask)
 {
-    LLKeyConflict &type_data = mControlsMap[control_type];
+    if (control_name.empty())
+    {
+        return false;
+    }
+    LLKeyConflict &type_data = mControlsMap[control_name];
     if (!type_data.mAssignable)
     {
         LL_ERRS() << "Error in code, user or system should not be able to change certain controls" << LL_ENDL;
@@ -319,9 +195,13 @@ bool LLKeyConflictHandler::registerControl(EControlTypes control_type, U32 index
     return false;
 }
 
-LLKeyData LLKeyConflictHandler::getControl(EControlTypes control_type, U32 index)
+LLKeyData LLKeyConflictHandler::getControl(const std::string &control_name, U32 index)
 {
-    return mControlsMap[control_type].getKeyData(index);
+    if (control_name.empty())
+    {
+        return LLKeyData();
+    }
+    return mControlsMap[control_name].getKeyData(index);
 }
 
 // static
@@ -341,24 +221,37 @@ std::string LLKeyConflictHandler::getStringFromKeyData(const LLKeyData& keydata)
     {
         result = LLKeyboard::stringFromAccelerator(keydata.mMask);
     }
+    else if (keydata.mIgnoreMasks)
+    {
+        result = "acc+";
+    }
 
     result += string_from_mouse(keydata.mMouse);
 
     return result;
 }
 
-// static
-std::string LLKeyConflictHandler::getControlName(EControlTypes control_type)
+std::string LLKeyConflictHandler::getControlString(const std::string &control_name, U32 index)
 {
-    return typetostring[control_type];
+    if (control_name.empty())
+    {
+        return "";
+    }
+    return getStringFromKeyData(mControlsMap[control_name].getKeyData(index));
 }
 
-std::string LLKeyConflictHandler::getControlString(EControlTypes control_type, U32 index)
+void LLKeyConflictHandler::loadFromControlSettings(const std::string &name)
 {
-    return getStringFromKeyData(mControlsMap[control_type].getKeyData(index));
+    LLControlVariablePtr var = gSavedSettings.getControl(name);
+    if (var)
+    {
+        LLKeyBind bind(var->getValue());
+        LLKeyConflict key(bind, true, 0);
+        mControlsMap[name] = key;
+    }
 }
 
-void  LLKeyConflictHandler::loadFromSettings(const LLViewerInput::KeyMode& keymode, control_map_t *destination)
+void LLKeyConflictHandler::loadFromSettings(const LLViewerInput::KeyMode& keymode, control_map_t *destination)
 {
     for (LLInitParam::ParamIterator<LLViewerInput::KeyBinding>::const_iterator it = keymode.bindings.begin(),
         end_it = keymode.bindings.end();
@@ -378,28 +271,23 @@ void  LLKeyConflictHandler::loadFromSettings(const LLViewerInput::KeyMode& keymo
             LLKeyboard::keyFromString(it->key, &key);
         }
         LLKeyboard::maskFromString(it->mask, &mask);
-        std::string command_name = it->command;
-        // it->command
-        // It might be better to have <string,bind> 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(mouse, key, mask, ignore);
-        }
+        // Note: it->command is also the name of UI element, howhever xml we are loading from
+        // might not know all the commands, so UI will have to know what to fill by its own
+        LLKeyConflict &type_data = (*destination)[it->command];
+        type_data.mAssignable = true;
+        type_data.mKeyBind.addKeyData(mouse, key, mask, ignore);
     }
 }
 
-void LLKeyConflictHandler::loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination)
+bool LLKeyConflictHandler::loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination)
 {
     if (filename.empty())
     {
-        return;
+        return false;
     }
 
+    bool res = false;
+
     LLViewerInput::Keys keys;
     LLSimpleXUIParser parser;
 
@@ -412,39 +300,45 @@ void LLKeyConflictHandler::loadFromSettings(const ESourceMode &load_mode, const
             if (keys.first_person.isProvided())
             {
                 loadFromSettings(keys.first_person, destination);
+                res = true;
             }
             break;
         case MODE_THIRD_PERSON:
             if (keys.third_person.isProvided())
             {
                 loadFromSettings(keys.third_person, destination);
+                res = true;
             }
             break;
         case MODE_EDIT:
             if (keys.edit.isProvided())
             {
                 loadFromSettings(keys.edit, destination);
+                res = true;
             }
             break;
         case MODE_EDIT_AVATAR:
             if (keys.edit_avatar.isProvided())
             {
                 loadFromSettings(keys.edit_avatar, destination);
+                res = true;
             }
             break;
         case MODE_SITTING:
             if (keys.sitting.isProvided())
             {
                 loadFromSettings(keys.sitting, destination);
+                res = true;
             }
             break;
         default:
             break;
         }
     }
+    return res;
 }
 
-void  LLKeyConflictHandler::loadFromSettings(ESourceMode load_mode)
+void LLKeyConflictHandler::loadFromSettings(ESourceMode load_mode)
 {
     mControlsMap.clear();
     mDefaultsMap.clear();
@@ -454,48 +348,26 @@ void  LLKeyConflictHandler::loadFromSettings(ESourceMode load_mode)
 
     if (load_mode == MODE_GENERAL)
     {
-        for (U32 i = 0; i < CONTROL_NUM_INDICES; i++)
+        // load settings clss knows about, but it also possible to load settings by name separately
+        const S32 size = std::extent<decltype(saved_settings_key_controls)>::value;
+        for (U32 i = 0; i < size; 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;
-                }
-            }
+            loadFromControlSettings(saved_settings_key_controls[i]);
         }
     }
     else
     {
         // load defaults
         std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "keys.xml");
-        loadFromSettings(load_mode, filename, &mDefaultsMap);
+        if (!loadFromSettings(load_mode, filename, &mDefaultsMap))
+        {
+            LL_WARNS() << "Failed to load default settings, aborting" << LL_ENDL;
+            return;
+        }
 
         // load user's
         filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "keys.xml");
-        if (gDirUtilp->fileExists(filename))
-        {
-            loadFromSettings(load_mode, filename, &mControlsMap);
-        }
-        else
+        if (!gDirUtilp->fileExists(filename) || loadFromSettings(load_mode, filename, &mControlsMap))
         {
             // mind placeholders
             mControlsMap.insert(mDefaultsMap.begin(), mDefaultsMap.end());
@@ -504,7 +376,7 @@ void  LLKeyConflictHandler::loadFromSettings(ESourceMode load_mode)
     mLoadMode = load_mode;
 }
 
-void  LLKeyConflictHandler::saveToSettings()
+void LLKeyConflictHandler::saveToSettings()
 {
     if (mControlsMap.empty())
     {
@@ -513,39 +385,33 @@ void  LLKeyConflictHandler::saveToSettings()
 
     if (mLoadMode == MODE_GENERAL)
     {
-        for (U32 i = 0; i < CONTROL_NUM_INDICES; i++)
+        control_map_t::iterator iter = mControlsMap.begin();
+        control_map_t::iterator end = mControlsMap.end();
+
+        for (; iter != end; ++iter)
         {
-            EControlTypes type = (EControlTypes)i;
-            switch (type)
+            if (iter->first.empty())
             {
-            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:
+                continue;
+            }
+
+            LLKeyConflict &key = iter->second;
+            key.mKeyBind.trimEmpty();
+            if (!key.mAssignable)
             {
-                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;
+                continue;
+            }
+
+            if (gSavedSettings.controlExists(iter->first))
+            {
+                gSavedSettings.setLLSD(iter->first, key.mKeyBind.asLLSD());
             }
+            else if (!key.mKeyBind.empty())
+            {
+                // Note: this is currently not in use, might be better for load mechanics to ask for and retain control group
+                // otherwise settings loaded from other control groups will end in this one
+                LL_INFOS() << "Creating new keybinding " << iter->first << LL_ENDL;
+                gSavedSettings.declareLLSD(iter->first, key.mKeyBind.asLLSD(), "comment", LLControlVariable::PERSIST_ALWAYS);
             }
         }
     }
@@ -564,8 +430,8 @@ void  LLKeyConflictHandler::saveToSettings()
         {
             // replace category we edited
 
-            // todo: fix this
-            // workaround to avoid doing own param container 
+            // mode is a HACK to correctly reset bindings without reparsing whole file and avoid doing
+            // own param container (which will face issues with inasseesible members of LLInitParam)
             LLViewerInput::KeyMode mode;
             LLViewerInput::KeyBinding binding;
 
@@ -581,8 +447,20 @@ void  LLKeyConflictHandler::saveToSettings()
                 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 (iter->first.empty())
+                    {
+                        continue;
+                    }
+
+                    LLKeyConflict &key = iter->second;
+                    key.mKeyBind.trimEmpty();
+                    if (key.mKeyBind.empty() || !key.mAssignable)
+                    {
+                        continue;
+                    }
+
+                    LLKeyData data = key.mKeyBind.getKeyData(i);
+                    // Still write empty LLKeyData to make sure we will maintain UI position
                     if (data.mKey == KEY_NONE)
                     {
                         binding.key = "";
@@ -595,7 +473,7 @@ void  LLKeyConflictHandler::saveToSettings()
                     binding.mask = string_from_mask(data.mMask);
                     binding.mouse.set(string_from_mouse(data.mMouse), true); //set() because 'optional', for compatibility purposes
                     binding.ignore.set(data.mIgnoreMasks, true);
-                    binding.command = getControlName(iter->first);
+                    binding.command = iter->first;
                     mode.bindings.add(binding);
                 }
             }
@@ -664,12 +542,15 @@ void  LLKeyConflictHandler::saveToSettings()
     mHasUnsavedChanges = false;
 }
 
-LLKeyData LLKeyConflictHandler::getDefaultControl(EControlTypes control_type, U32 index)
+LLKeyData LLKeyConflictHandler::getDefaultControl(const std::string &control_name, U32 index)
 {
+    if (control_name.empty())
+    {
+        return LLKeyData();
+    }
     if (mLoadMode == MODE_GENERAL)
     {
-        std::string name = getControlName(control_type);
-        LLControlVariablePtr var = gSavedSettings.getControl(name);
+        LLControlVariablePtr var = gSavedSettings.getControl(control_name);
         if (var)
         {
             return LLKeyBind(var->getDefault()).getKeyData(index);
@@ -678,7 +559,7 @@ LLKeyData LLKeyConflictHandler::getDefaultControl(EControlTypes control_type, U3
     }
     else
     {
-        control_map_t::iterator iter = mDefaultsMap.find(control_type);
+        control_map_t::iterator iter = mDefaultsMap.find(control_name);
         if (iter != mDefaultsMap.end())
         {
             return iter->second.mKeyBind.getKeyData(index);
@@ -687,24 +568,31 @@ LLKeyData LLKeyConflictHandler::getDefaultControl(EControlTypes control_type, U3
     }
 }
 
-void LLKeyConflictHandler::resetToDefault(EControlTypes control_type, U32 index)
+void LLKeyConflictHandler::resetToDefault(const std::string &control_name, U32 index)
 {
-    LLKeyData data = getDefaultControl(control_type, index);
+    if (control_name.empty())
+    {
+        return;
+    }
+    LLKeyData data = getDefaultControl(control_name, index);
 
-    if (data != mControlsMap[control_type].getKeyData(index))
+    if (data != mControlsMap[control_name].getKeyData(index))
     {
         // reset controls that might have been switched to our current control
-        removeConflicts(data, mControlsMap[control_type].mConflictMask);
-        mControlsMap[control_type].setKeyData(data, index);
+        removeConflicts(data, mControlsMap[control_name].mConflictMask);
+        mControlsMap[control_name].setKeyData(data, index);
     }
 }
 
-void LLKeyConflictHandler::resetToDefaultAndResolve(EControlTypes control_type, bool ignore_conflicts)
+void LLKeyConflictHandler::resetToDefaultAndResolve(const std::string &control_name, bool ignore_conflicts)
 {
+    if (control_name.empty())
+    {
+        return;
+    }
     if (mLoadMode == MODE_GENERAL)
     {
-        std::string name = getControlName(control_type);
-        LLControlVariablePtr var = gSavedSettings.getControl(name);
+        LLControlVariablePtr var = gSavedSettings.getControl(control_name);
         if (var)
         {
             LLKeyBind bind(var->getDefault());
@@ -712,67 +600,53 @@ void LLKeyConflictHandler::resetToDefaultAndResolve(EControlTypes control_type,
             {
                 for (S32 i = 0; i < bind.getDataCount(); ++i)
                 {
-                    removeConflicts(bind.getKeyData(i), mControlsMap[control_type].mConflictMask);
+                    removeConflicts(bind.getKeyData(i), mControlsMap[control_name].mConflictMask);
                 }
             }
-            mControlsMap[control_type].mKeyBind = bind;
+            mControlsMap[control_name].mKeyBind = bind;
         }
         else
         {
-            mControlsMap[control_type].mKeyBind.clear();
+            mControlsMap[control_name].mKeyBind.clear();
         }
     }
     else
     {
-        control_map_t::iterator iter = mDefaultsMap.find(control_type);
+        control_map_t::iterator iter = mDefaultsMap.find(control_name);
         if (iter != mDefaultsMap.end())
         {
             if (!ignore_conflicts)
             {
                 for (S32 i = 0; i < iter->second.mKeyBind.getDataCount(); ++i)
                 {
-                    removeConflicts(iter->second.mKeyBind.getKeyData(i), mControlsMap[control_type].mConflictMask);
+                    removeConflicts(iter->second.mKeyBind.getKeyData(i), mControlsMap[control_name].mConflictMask);
                 }
             }
-            mControlsMap[control_type].mKeyBind = iter->second.mKeyBind;
+            mControlsMap[control_name].mKeyBind = iter->second.mKeyBind;
         }
         else
         {
-            mControlsMap[control_type].mKeyBind.clear();
+            mControlsMap[control_name].mKeyBind.clear();
         }
     }
 }
 
-void LLKeyConflictHandler::resetToDefault(EControlTypes control_type)
+void LLKeyConflictHandler::resetToDefault(const std::string &control_name)
 {
     // reset specific binding without ignoring conflicts
-    resetToDefaultAndResolve(control_type, false);
+    resetToDefaultAndResolve(control_name, false);
 }
 
 void LLKeyConflictHandler::resetToDefaults(ESourceMode mode)
 {
     if (mode == MODE_GENERAL)
     {
-        for (U32 i = 0; i < CONTROL_NUM_INDICES; i++)
+        control_map_t::iterator iter = mControlsMap.begin();
+        control_map_t::iterator end = mControlsMap.end();
+
+        for (; iter != end; ++iter)
         {
-            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:
-            {
-                resetToDefaultAndResolve(type, true);
-                break;
-            }
-            }
+            resetToDefaultAndResolve(iter->first, true);
         }
     }
     else
@@ -834,7 +708,7 @@ bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, const U32 &con
         // Can't conflict
         return true;
     }
-    std::map<EControlTypes, S32> conflict_list;
+    std::map<std::string, S32> conflict_list;
     control_map_t::iterator cntrl_iter = mControlsMap.begin();
     control_map_t::iterator cntrl_end = mControlsMap.end();
     for (; cntrl_iter != cntrl_end; ++cntrl_iter)
@@ -859,8 +733,8 @@ bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, const U32 &con
         }
     }
 
-    std::map<EControlTypes, S32>::iterator cnflct_iter = conflict_list.begin();
-    std::map<EControlTypes, S32>::iterator cnflct_end = conflict_list.end();
+    std::map<std::string, S32>::iterator cnflct_iter = conflict_list.begin();
+    std::map<std::string, S32>::iterator cnflct_end = conflict_list.end();
     for (; cnflct_iter != cnflct_end; ++cnflct_iter)
     {
         mControlsMap[cnflct_iter->first].mKeyBind.resetKeyData(cnflct_iter->second);
@@ -868,9 +742,9 @@ bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, const U32 &con
     return true;
 }
 
-void LLKeyConflictHandler::registerTemporaryControl(EControlTypes control_type, EMouseClickType mouse, KEY key, MASK mask, U32 conflict_mask)
+void LLKeyConflictHandler::registerTemporaryControl(const std::string &control_name, EMouseClickType mouse, KEY key, MASK mask, U32 conflict_mask)
 {
-    LLKeyConflict *type_data = &mControlsMap[control_type];
+    LLKeyConflict *type_data = &mControlsMap[control_name];
     type_data->mAssignable = false;
     type_data->mConflictMask = conflict_mask;
     type_data->mKeyBind.addKeyData(mouse, key, mask, false);
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index e4a6da30d0..a0886bedce 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -70,114 +70,35 @@ public:
     // at the moment this just means that key will conflict with everything that is identical
     const U32 CONFLICT_ANY = U32_MAX;
 
-    // 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_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_SIT,
-        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_PAUSE_MEDIA, // Play pause
-        CONTROL_ENABLE_MEDIA, // Play stop
-        CONTROL_VOICE, // Keep pressing for voice 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(ESourceMode 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);
-    bool registerControl(EControlTypes control_type, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask, bool ignore_mask); //todo: return conflicts?
-
-    LLKeyData getControl(EControlTypes control_type, U32 data_index);
+    bool canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask);
+    bool canHandleKey(const std::string &control_name, KEY key, MASK mask);
+    bool canHandleMouse(const std::string &control_name, EMouseClickType mouse_ind, MASK mask);
+    bool canHandleMouse(const std::string &control_name, S32 mouse_ind, MASK mask); //Just for convinience
+    bool canAssignControl(const std::string &control_name);
+    bool registerControl(const std::string &control_name, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask, bool ignore_mask); //todo: return conflicts?
 
-    static std::string LLKeyConflictHandler::getStringFromKeyData(const LLKeyData& keydata);
-    static std::string getControlName(EControlTypes control_type);
-    std::string getControlString(EControlTypes control_type, U32 data_index);
+    LLKeyData getControl(const std::string &control_name, U32 data_index);
 
+    static std::string getStringFromKeyData(const LLKeyData& keydata);
+    std::string getControlString(const std::string &control_name, U32 data_index);
 
+    // Load single control, overrides existing one if names match
+    void loadFromControlSettings(const std::string &name);
     // Drops any changes loads controls with ones from 'saved settings' or from xml
     void loadFromSettings(ESourceMode load_mode);
     // Saves settings to 'saved settings' or to xml
     void saveToSettings();
 
-    LLKeyData getDefaultControl(EControlTypes control_type, U32 data_index);
+    LLKeyData getDefaultControl(const std::string &control_name, 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);
-    // resets current mode to defaults, 
+    void resetToDefault(const std::string &control_name, U32 index);
+    void resetToDefault(const std::string &control_name);
+    // resets current mode to defaults
     void resetToDefaults();
 
     bool empty() { return mControlsMap.empty(); }
@@ -188,15 +109,15 @@ public:
     ESourceMode getLoadMode() { return mLoadMode; }
 
 private:
-    void resetToDefaultAndResolve(EControlTypes control_type, bool ignore_conflicts);
+    void resetToDefaultAndResolve(const std::string &control_name, bool ignore_conflicts);
     void resetToDefaults(ESourceMode mode);
 
     // 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);
+    void registerTemporaryControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask, U32 conflict_mask);
 
-    typedef std::map<EControlTypes, LLKeyConflict> control_map_t;
+    typedef std::map<std::string, LLKeyConflict> control_map_t;
     void loadFromSettings(const LLViewerInput::KeyMode& keymode, control_map_t *destination);
-    void loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination);
+    bool loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination);
     void resetKeyboardBindings();
     void generatePlaceholders(ESourceMode load_mode); //E.x. non-assignable values
     // returns false in case user is trying to reuse control that can't be reassigned
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index 11f430cda3..eff578cf26 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -648,6 +648,78 @@ bool start_gesture( EKeystate s )
 	return true;
 }
 
+bool run_forward(EKeystate s)
+{
+    if (KEYSTATE_DOWN == s)
+    {
+        gAgent.setAlwaysRun();
+        gAgent.setRunning();
+        gAgent.sendWalkRun(true);
+    }
+    else if(KEYSTATE_UP == s)
+    {
+        gAgent.clearAlwaysRun();
+        gAgent.clearRunning();
+        gAgent.sendWalkRun(false);
+    }
+    agent_push_forward(s);
+    return true;
+}
+
+bool run_backward(EKeystate s)
+{
+    if (KEYSTATE_DOWN == s)
+    {
+        gAgent.setAlwaysRun();
+        gAgent.setRunning();
+        gAgent.sendWalkRun(true);
+    }
+    else if (KEYSTATE_UP == s)
+    {
+        gAgent.clearAlwaysRun();
+        gAgent.clearRunning();
+        gAgent.sendWalkRun(false);
+    }
+    agent_push_backward(s);
+    return true;
+}
+
+bool run_left(EKeystate s)
+{
+    if (KEYSTATE_DOWN == s)
+    {
+        gAgent.setAlwaysRun();
+        gAgent.setRunning();
+        gAgent.sendWalkRun(true);
+    }
+    else if (KEYSTATE_UP == s)
+    {
+        gAgent.clearAlwaysRun();
+        gAgent.clearRunning();
+        gAgent.sendWalkRun(false);
+    }
+    agent_slide_left(s);
+    return true;
+}
+
+bool run_right(EKeystate s)
+{
+    if (KEYSTATE_DOWN == s)
+    {
+        gAgent.setAlwaysRun();
+        gAgent.setRunning();
+        gAgent.sendWalkRun(true);
+    }
+    else if (KEYSTATE_UP == s)
+    {
+        gAgent.clearAlwaysRun();
+        gAgent.clearRunning();
+        gAgent.sendWalkRun(false);
+    }
+    agent_slide_right(s);
+    return true;
+}
+
 bool toggle_run(EKeystate s)
 {
     if (KEYSTATE_DOWN != s) return true;
@@ -789,6 +861,10 @@ 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("run_forward", run_forward);
+REGISTER_KEYBOARD_ACTION("run_backward", run_backward);
+REGISTER_KEYBOARD_ACTION("run_left", run_left);
+REGISTER_KEYBOARD_ACTION("run_right", run_right);
 REGISTER_KEYBOARD_ACTION("toggle_run", toggle_run);
 REGISTER_KEYBOARD_ACTION("toggle_sit", toggle_sit);
 REGISTER_KEYBOARD_ACTION("toggle_pause_media", toggle_pause_media);
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 5388d13a04..3c2ec369ec 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -955,6 +955,8 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK m
 		case CLICK_BUTTON5:
 			buttonname = "Button 5";
 			break;
+		default:
+			break; // COUNT and NONE
 		}
 		
 		LLView::sMouseHandlerMessage.clear();
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
index 62267dce8a..385d4796a0 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
@@ -9,6 +9,10 @@
  name="controls"
  top="1"
  width="517">
+  <panel.string
+   name="walk_to">
+    Walk to
+  </panel.string>
   <panel.string
    name="control_view_actions">
     View Actions
@@ -70,8 +74,8 @@
     Move Actions
   </panel.string>
   <panel.string
-   name="control_moveto">
-    Move To
+   name="teleport_to">
+    Teleport to
   </panel.string>
   <panel.string
    name="toggle_sit">
@@ -118,6 +122,22 @@
    name="control_run">
     Run
   </panel.string>
+  <panel.string
+   name="run_forward">
+    Run Forward
+  </panel.string>
+  <panel.string
+   name="run_backward">
+    Run Backward
+  </panel.string>
+  <panel.string
+   name="run_left">
+    Run Left
+  </panel.string>
+  <panel.string
+   name="run_right">
+    Run Right
+  </panel.string>
   <panel.string
    name="toggle_run">
     Toggle Run
@@ -126,6 +146,10 @@
    name="toggle_fly">
     Fly/Stop flying
   </panel.string>
+  <panel.string
+   name="stop_moving">
+    Stop Moving
+  </panel.string>
   <panel.string
    name="control_camera">
     Camera
@@ -215,36 +239,13 @@
     Play/Stop All Media
   </panel.string>
   <panel.string
-   name="control_voice">
+   name="voice_follow_key">
     Voice
   </panel.string>
   <panel.string
-   name="control_toggle_voice">
+   name="toggle_voice">
     Toggle Voice
   </panel.string>
-  <panel.string
-   name="control_reserved">
-    Reserved Controls
-  </panel.string>
-  <panel.string
-   name="control_delete">
-    Delete
-  </panel.string>
-  <!--
-   name="control_menu" not needed
-   -->
-  <panel.string
-   name="control_reserved_select">
-    Select
-  </panel.string>
-  <panel.string
-   name="control_shift_select">
-    Multi-Select
-  </panel.string>
-  <panel.string
-   name="control_cntrl_select">
-    Add to Selection
-  </panel.string>
 
   <combo_box
    follows="top|left"
-- 
cgit v1.2.3


From d61601289110b0e406e70bf65ced2c4a1e110760 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Tue, 1 Oct 2019 20:35:59 +0300
Subject: SL-6109 Implemented LLDrawFrustum

---
 indra/newview/CMakeLists.txt                |   2 +
 indra/newview/lldrawfrustum.cpp             | 113 ++++++++++++++++++++++++++++
 indra/newview/lldrawfrustum.h               |  55 ++++++++++++++
 indra/newview/llfloateravatarpicker.cpp     |  75 +-----------------
 indra/newview/llfloateravatarpicker.h       |   9 +--
 indra/newview/llfloatercolorpicker.cpp      |  59 +--------------
 indra/newview/llfloatercolorpicker.h        |  11 +--
 indra/newview/llfloaterexperiencepicker.cpp |  72 +-----------------
 indra/newview/llfloaterexperiencepicker.h   |  10 +--
 indra/newview/lltexturectrl.cpp             |  62 +--------------
 indra/newview/lltexturectrl.h               |   6 +-
 11 files changed, 194 insertions(+), 280 deletions(-)
 create mode 100644 indra/newview/lldrawfrustum.cpp
 create mode 100644 indra/newview/lldrawfrustum.h

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 9a72fcc228..a35d0cba50 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -179,6 +179,7 @@ set(viewer_SOURCE_FILES
     lldonotdisturbnotificationstorage.cpp
     lldndbutton.cpp
     lldrawable.cpp
+    lldrawfrustum.cpp
     lldrawpool.cpp
     lldrawpoolalpha.cpp
     lldrawpoolavatar.cpp
@@ -807,6 +808,7 @@ set(viewer_HEADER_FILES
     lldonotdisturbnotificationstorage.h
     lldndbutton.h
     lldrawable.h
+    lldrawfrustum.h
     lldrawpool.h
     lldrawpoolalpha.h
     lldrawpoolavatar.h
diff --git a/indra/newview/lldrawfrustum.cpp b/indra/newview/lldrawfrustum.cpp
new file mode 100644
index 0000000000..1d583223c8
--- /dev/null
+++ b/indra/newview/lldrawfrustum.cpp
@@ -0,0 +1,113 @@
+/** 
+* @file lldrawfrustum.cpp
+* @brief Implementation of lldrawfrustum
+*
+* $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$
+*/
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lldrawfrustum.h"
+
+#include "llviewercontrol.h"
+
+LLDrawFrustum::LLDrawFrustum()
+    : mContextConeOpacity(0.f)
+{
+    mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha"); // 0.0f
+    mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha"); // 1.f
+    mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime"); // 0.08f
+}
+
+LLDrawFrustum::LLDrawFrustum(LLView *origin)
+    : mContextConeOpacity(0.f)
+{
+    mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
+    mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
+    mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
+    setFrustumOrigin(origin);
+}
+
+void LLDrawFrustum::setFrustumOrigin(LLView *origin)
+{
+    if (origin)
+    {
+        mFrustumOrigin = origin->getHandle();
+    }
+}
+
+void LLDrawFrustum::drawFrustum(const LLRect &derived_local_rect, const LLView *root_view, const LLView *drag_handle, bool has_focus)
+{
+    if (mFrustumOrigin.get())
+    {
+        LLView * frustumOrigin = mFrustumOrigin.get();
+        LLRect origin_rect;
+        frustumOrigin->localRectToOtherView(frustumOrigin->getLocalRect(), &origin_rect, root_view);
+        // draw context cone connecting derived floater (ex: color picker) with view (ex: color swatch) in parent floater
+        if (has_focus && frustumOrigin->isInVisibleChain() && mContextConeOpacity > 0.001f)
+        {
+            gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+            LLGLEnable(GL_CULL_FACE);
+            gGL.begin(LLRender::QUADS);
+            {
+                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+                gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
+                gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
+                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+                gGL.vertex2i(derived_local_rect.mRight, derived_local_rect.mTop);
+                gGL.vertex2i(derived_local_rect.mLeft, derived_local_rect.mTop);
+
+                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+                gGL.vertex2i(derived_local_rect.mLeft, derived_local_rect.mTop);
+                gGL.vertex2i(derived_local_rect.mLeft, derived_local_rect.mBottom);
+                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+                gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
+                gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
+
+                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+                gGL.vertex2i(derived_local_rect.mRight, derived_local_rect.mBottom);
+                gGL.vertex2i(derived_local_rect.mRight, derived_local_rect.mTop);
+                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+                gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
+                gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
+
+                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+                gGL.vertex2i(derived_local_rect.mLeft, derived_local_rect.mBottom);
+                gGL.vertex2i(derived_local_rect.mRight, derived_local_rect.mBottom);
+                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+                gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
+                gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
+            }
+            gGL.end();
+        }
+
+        if (gFocusMgr.childHasMouseCapture(drag_handle))
+        {
+            mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(mContextConeFadeTime));
+        }
+        else
+        {
+            mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(mContextConeFadeTime));
+        }
+    }
+}
+
diff --git a/indra/newview/lldrawfrustum.h b/indra/newview/lldrawfrustum.h
new file mode 100644
index 0000000000..f6f62d737c
--- /dev/null
+++ b/indra/newview/lldrawfrustum.h
@@ -0,0 +1,55 @@
+/** 
+* @file   lldrawfrustum.h
+* @brief  Header file for lldrawfrustum
+*
+* $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_LLDRAWFRUSTUM_H
+#define LL_LLDRAWFRUSTUM_H
+
+#include "llview.h" 
+
+class LLDrawFrustum
+{
+public:
+    LLDrawFrustum();
+    LLDrawFrustum(LLView *origin);
+protected:
+
+    // Draw's a cone from origin to derived view or floater
+    // @derived_local_rect derived flaoter's local rect
+    // @droot_view usually it is a derived floater
+    // @drag_handle floater's drag handle getDragHandle()
+    void drawFrustum(const LLRect &derived_local_rect, const LLView *root_view, const LLView *drag_handle, bool has_focus);
+
+    void setFrustumOrigin(LLView *origin);
+private:
+
+    LLHandle <LLView>   mFrustumOrigin;
+    F32		            mContextConeOpacity;
+    F32                 mContextConeInAlpha;
+    F32                 mContextConeOutAlpha;
+    F32                 mContextConeFadeTime;
+};
+
+#endif // LL_LLDRAWFRUSTUM_H
+
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index 33099db1b9..e86c10d00b 100644
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -81,6 +81,7 @@ LLFloaterAvatarPicker* LLFloaterAvatarPicker::show(select_callback_t callback,
 	floater->mNearMeListComplete = FALSE;
 	floater->mCloseOnSelect = closeOnSelect;
 	floater->mExcludeAgentFromSearchResults = skip_agent;
+    floater->setFrustumOrigin(frustumOrigin);
 	
 	if (!closeOnSelect)
 	{
@@ -91,10 +92,6 @@ LLFloaterAvatarPicker* LLFloaterAvatarPicker::show(select_callback_t callback,
 		floater->getChild<LLButton>("cancel_btn")->setLabel(close_string);
 	}
 
-    if(frustumOrigin)
-    {
-        floater->mFrustumOrigin = frustumOrigin->getHandle();
-    }
 
 	return floater;
 }
@@ -104,17 +101,9 @@ LLFloaterAvatarPicker::LLFloaterAvatarPicker(const LLSD& key)
   : LLFloater(key),
 	mNumResultsReturned(0),
 	mNearMeListComplete(FALSE),
-	mCloseOnSelect(FALSE),
-    mContextConeOpacity	(0.f),
-    mContextConeInAlpha(0.f),
-    mContextConeOutAlpha(0.f),
-    mContextConeFadeTime(0.f)
+	mCloseOnSelect(FALSE)
 {
 	mCommitCallbackRegistrar.add("Refresh.FriendList", boost::bind(&LLFloaterAvatarPicker::populateFriend, this));
-
-    mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
-    mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
-    mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
 }
 
 BOOL LLFloaterAvatarPicker::postBuild()
@@ -359,66 +348,10 @@ void LLFloaterAvatarPicker::populateFriend()
 	friends_scroller->sortByColumnIndex(0, TRUE);
 }
 
-void LLFloaterAvatarPicker::drawFrustum()
-{
-    if(mFrustumOrigin.get())
-    {
-        LLView * frustumOrigin = mFrustumOrigin.get();
-        LLRect origin_rect;
-        frustumOrigin->localRectToOtherView(frustumOrigin->getLocalRect(), &origin_rect, this);
-        // draw context cone connecting color picker with color swatch in parent floater
-        LLRect local_rect = getLocalRect();
-        if (hasFocus() && frustumOrigin->isInVisibleChain() && mContextConeOpacity > 0.001f)
-        {
-            gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-            LLGLEnable(GL_CULL_FACE);
-            gGL.begin(LLRender::QUADS);
-            {
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-                gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
-                gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-                gGL.vertex2i(local_rect.mRight, local_rect.mTop);
-                gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
-
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-                gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
-                gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-                gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
-                gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
-
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-                gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
-                gGL.vertex2i(local_rect.mRight, local_rect.mTop);
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-                gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
-                gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
-
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-                gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
-                gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-                gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
-                gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
-            }
-            gGL.end();
-        }
-
-        if (gFocusMgr.childHasMouseCapture(getDragHandle()))
-        {
-            mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLSmoothInterpolation::getInterpolant(mContextConeFadeTime));
-        }
-        else
-        {
-            mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(mContextConeFadeTime));
-        }
-    }
-}
-
 void LLFloaterAvatarPicker::draw()
 {
-    drawFrustum();
+    LLRect local_rect = getLocalRect();
+    drawFrustum(local_rect, this, getDragHandle(), hasFocus());
 
 	// sometimes it is hard to determine when Select/Ok button should be disabled (see LLAvatarActions::shareWithAvatars).
 	// lets check this via mOkButtonValidateSignal callback periodically.
diff --git a/indra/newview/llfloateravatarpicker.h b/indra/newview/llfloateravatarpicker.h
index fbee61b054..7d94199786 100644
--- a/indra/newview/llfloateravatarpicker.h
+++ b/indra/newview/llfloateravatarpicker.h
@@ -28,6 +28,7 @@
 #define LLFLOATERAVATARPICKER_H
 
 #include "llfloater.h"
+#include "lldrawfrustum.h"
 #include "lleventcoro.h"
 #include "llcoros.h"
 
@@ -36,7 +37,7 @@
 class LLAvatarName;
 class LLScrollListCtrl;
 
-class LLFloaterAvatarPicker :public LLFloater
+class LLFloaterAvatarPicker :public LLFloater, public LLDrawFrustum
 {
 public:
 	typedef boost::signals2::signal<bool(const uuid_vec_t&), boost_boolean_combiner> validate_signal_t;
@@ -91,7 +92,6 @@ private:
 	void setAllowMultiple(BOOL allow_multiple);
 	LLScrollListCtrl* getActiveList();
 
-    void drawFrustum();
 	virtual void draw();
 	virtual BOOL handleKeyHere(KEY key, MASK mask);
 
@@ -100,11 +100,6 @@ private:
 	BOOL				mNearMeListComplete;
 	BOOL				mCloseOnSelect;
 	BOOL                mExcludeAgentFromSearchResults;
-    LLHandle <LLView>   mFrustumOrigin;
-    F32		            mContextConeOpacity;
-    F32                 mContextConeInAlpha;
-    F32                 mContextConeOutAlpha;
-    F32                 mContextConeFadeTime;
 
 	validate_signal_t mOkButtonValidateSignal;
 	select_callback_t mSelectionCallback;
diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp
index ec2c9740af..9c06f777fb 100644
--- a/indra/newview/llfloatercolorpicker.cpp
+++ b/indra/newview/llfloatercolorpicker.cpp
@@ -70,6 +70,7 @@
 
 LLFloaterColorPicker::LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show_apply_immediate )
 	: LLFloater(LLSD()),
+      LLDrawFrustum(swatch),
 	  mComponents			( 3 ),
 	  mMouseDownInLumRegion	( FALSE ),
 	  mMouseDownInHueRegion	( FALSE ),
@@ -100,11 +101,7 @@ LLFloaterColorPicker::LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show
 	  mPaletteRegionHeight	( 40 ),
 	  mSwatch				( swatch ),
 	  mActive				( TRUE ),
-	  mCanApplyImmediately	( show_apply_immediate ),
-	  mContextConeOpacity	( 0.f ),
-      mContextConeInAlpha   ( 0.f ),
-      mContextConeOutAlpha   ( 0.f ),
-      mContextConeFadeTime   ( 0.f )
+	  mCanApplyImmediately	( show_apply_immediate )
 {
 	buildFromFile ( "floater_color_picker.xml");
 
@@ -116,10 +113,6 @@ LLFloaterColorPicker::LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show
 		mApplyImmediateCheck->setEnabled(FALSE);
 		mApplyImmediateCheck->set(FALSE);
 	}
-
-    mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
-    mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
-    mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
 }
 
 LLFloaterColorPicker::~LLFloaterColorPicker()
@@ -485,56 +478,10 @@ BOOL LLFloaterColorPicker::isColorChanged()
 //
 void LLFloaterColorPicker::draw()
 {
-	LLRect swatch_rect;
-	mSwatch->localRectToOtherView(mSwatch->getLocalRect(), &swatch_rect, this);
 	// draw context cone connecting color picker with color swatch in parent floater
 	LLRect local_rect = getLocalRect();
-	if (hasFocus() && mSwatch->isInVisibleChain() && mContextConeOpacity > 0.001f)
-	{
-		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-		LLGLEnable(GL_CULL_FACE);
-		gGL.begin(LLRender::QUADS);
-		{
-			gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mTop);
-			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mTop);
-			gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-			gGL.vertex2i(local_rect.mRight, local_rect.mTop);
-			gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
-
-			gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-			gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
-			gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
-			gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mBottom);
-			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mTop);
-
-			gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-			gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
-			gGL.vertex2i(local_rect.mRight, local_rect.mTop);
-			gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mTop);
-			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mBottom);
-
-			gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-			gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
-			gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
-			gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mBottom);
-			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mBottom);
-		}
-		gGL.end();
-	}
+	drawFrustum(local_rect, this, getDragHandle(), hasFocus());
 
-	if (gFocusMgr.childHasMouseCapture(getDragHandle()))
-	{
-		mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), 
-                                        LLSmoothInterpolation::getInterpolant(mContextConeFadeTime));
-	}
-	else
-	{
-		mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(mContextConeFadeTime));
-	}
 
 	mPipetteBtn->setToggleState(LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance());
 	mApplyImmediateCheck->setEnabled(mActive && mCanApplyImmediately);
diff --git a/indra/newview/llfloatercolorpicker.h b/indra/newview/llfloatercolorpicker.h
index 16974a872e..74b99d5e68 100644
--- a/indra/newview/llfloatercolorpicker.h
+++ b/indra/newview/llfloatercolorpicker.h
@@ -30,6 +30,7 @@
 #include <vector>
 
 #include "llfloater.h"
+#include "lldrawfrustum.h"
 #include "llpointer.h"
 #include "llcolorswatch.h"
 #include "llspinctrl.h"
@@ -41,7 +42,7 @@ class LLCheckBoxCtrl;
 //////////////////////////////////////////////////////////////////////////////
 // floater class
 class LLFloaterColorPicker 
-	: public LLFloater
+	: public LLFloater, public LLDrawFrustum
 {
 	public:
 		LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show_apply_immediate = FALSE);
@@ -63,7 +64,7 @@ class LLFloaterColorPicker
 		void destroyUI ();
 		void cancelSelection ();
 		LLColorSwatchCtrl* getSwatch () { return mSwatch; };
-		void setSwatch( LLColorSwatchCtrl* swatch) { mSwatch = swatch; }
+        void setSwatch(LLColorSwatchCtrl* swatch) { mSwatch = swatch; setFrustumOrigin(mSwatch); }
 
 		// mutator / accessor for original RGB value
 		void setOrigRgb ( F32 origRIn, F32 origGIn, F32 origBIn );
@@ -196,12 +197,6 @@ class LLFloaterColorPicker
 		LLButton* mCancelBtn;
 
 		LLButton* mPipetteBtn;
-
-		F32		  mContextConeOpacity;
-        F32       mContextConeInAlpha;
-        F32       mContextConeOutAlpha;
-        F32       mContextConeFadeTime;
-
 };
 
 #endif // LL_LLFLOATERCOLORPICKER_H
diff --git a/indra/newview/llfloaterexperiencepicker.cpp b/indra/newview/llfloaterexperiencepicker.cpp
index bb54c57baf..352b3a4ece 100644
--- a/indra/newview/llfloaterexperiencepicker.cpp
+++ b/indra/newview/llfloaterexperiencepicker.cpp
@@ -64,88 +64,22 @@ LLFloaterExperiencePicker* LLFloaterExperiencePicker::show( select_callback_t ca
 		floater->mSearchPanel->filterContent();
 	}
 
-	if(frustumOrigin)
-	{
-		floater->mFrustumOrigin = frustumOrigin->getHandle();
-	}
+	floater->setFrustumOrigin(frustumOrigin);
 
 	return floater;
 }
 
-void LLFloaterExperiencePicker::drawFrustum()
-{
-	if(mFrustumOrigin.get())
-	{
-		LLView * frustumOrigin = mFrustumOrigin.get();
-		LLRect origin_rect;
-		frustumOrigin->localRectToOtherView(frustumOrigin->getLocalRect(), &origin_rect, this);
-		// draw context cone connecting color picker with color swatch in parent floater
-		LLRect local_rect = getLocalRect();
-		if (hasFocus() && frustumOrigin->isInVisibleChain() && mContextConeOpacity > 0.001f)
-		{
-			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-			LLGLEnable(GL_CULL_FACE);
-			gGL.begin(LLRender::QUADS);
-			{
-				gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-				gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
-				gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
-				gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-				gGL.vertex2i(local_rect.mRight, local_rect.mTop);
-				gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
-
-				gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-				gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
-				gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
-				gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-				gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
-				gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
-
-				gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-				gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
-				gGL.vertex2i(local_rect.mRight, local_rect.mTop);
-				gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-				gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
-				gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
-
-				gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-				gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
-				gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
-				gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-				gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
-				gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
-			}
-			gGL.end();
-		}
-
-		if (gFocusMgr.childHasMouseCapture(getDragHandle()))
-		{
-			mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(mContextConeFadeTime));
-		}
-		else
-		{
-			mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(mContextConeFadeTime));
-		}
-	}
-}
-
 void LLFloaterExperiencePicker::draw()
 {
-	drawFrustum();
+    LLRect local_rect = getLocalRect();
+    drawFrustum(local_rect, this, getDragHandle(), hasFocus());
 	LLFloater::draw();
 }
 
 LLFloaterExperiencePicker::LLFloaterExperiencePicker( const LLSD& key )
 	:LLFloater(key)
 	,mSearchPanel(NULL)
-	,mContextConeOpacity(0.f)
-	,mContextConeInAlpha(0.f)
-	,mContextConeOutAlpha(0.f)
-	,mContextConeFadeTime(0.f)
 {
-	mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
-	mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
-	mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
 }
 
 LLFloaterExperiencePicker::~LLFloaterExperiencePicker()
diff --git a/indra/newview/llfloaterexperiencepicker.h b/indra/newview/llfloaterexperiencepicker.h
index 29054a57db..55fc632e18 100644
--- a/indra/newview/llfloaterexperiencepicker.h
+++ b/indra/newview/llfloaterexperiencepicker.h
@@ -28,13 +28,14 @@
 #define LL_LLFLOATEREXPERIENCEPICKER_H
 
 #include "llfloater.h"
+#include "lldrawfrustum.h"
 
 class LLScrollListCtrl;
 class LLLineEditor;
 class LLPanelExperiencePicker;
 
 
-class LLFloaterExperiencePicker : public LLFloater
+class LLFloaterExperiencePicker : public LLFloater, public LLDrawFrustum
 {
 public:
 
@@ -54,13 +55,6 @@ public:
 private:
 
 	LLPanelExperiencePicker* mSearchPanel;
-
-	void drawFrustum();
-	LLHandle <LLView>   mFrustumOrigin;
-	F32		            mContextConeOpacity;
-	F32                 mContextConeInAlpha;
-	F32                 mContextConeOutAlpha;
-	F32                 mContextConeFadeTime;
 };
 
 #endif // LL_LLFLOATEREXPERIENCEPICKER_H
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 8a2fc881a9..f10e0bdd81 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -73,10 +73,6 @@
 
 #include "llavatarappearancedefines.h"
 
-static const F32 CONTEXT_CONE_IN_ALPHA = 0.0f;
-static const F32 CONTEXT_CONE_OUT_ALPHA = 1.f;
-static const F32 CONTEXT_FADE_TIME = 0.08f;
-
 static const S32 LOCAL_TRACKING_ID_COLUMN = 1;
 
 //static const char CURRENT_IMAGE_NAME[] = "Current Texture";
@@ -113,7 +109,6 @@ LLFloaterTexturePicker::LLFloaterTexturePicker(
 	mImmediateFilterPermMask(immediate_filter_perm_mask),
 	mDnDFilterPermMask(dnd_filter_perm_mask),
 	mNonImmediateFilterPermMask(non_immediate_filter_perm_mask),
-	mContextConeOpacity(0.f),
 	mSelectedItemPinned( FALSE ),
 	mCanApply(true),
 	mCanPreview(true),
@@ -127,6 +122,7 @@ LLFloaterTexturePicker::LLFloaterTexturePicker(
 	buildFromFile("floater_texture_ctrl.xml");
 	mCanApplyImmediately = can_apply_immediately;
 	setCanMinimize(FALSE);
+	setFrustumOrigin(mOwner);
 }
 
 LLFloaterTexturePicker::~LLFloaterTexturePicker()
@@ -442,59 +438,9 @@ BOOL LLFloaterTexturePicker::postBuild()
 // virtual
 void LLFloaterTexturePicker::draw()
 {
-	if (mOwner)
-	{
-		// draw cone of context pointing back to texture swatch	
-		LLRect owner_rect;
-		mOwner->localRectToOtherView(mOwner->getLocalRect(), &owner_rect, this);
-		LLRect local_rect = getLocalRect();
-		if (gFocusMgr.childHasKeyboardFocus(this) && mOwner->isInVisibleChain() && mContextConeOpacity > 0.001f)
-		{
-			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-			LLGLEnable(GL_CULL_FACE);
-			gGL.begin(LLRender::QUADS);
-			{
-				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
-				gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
-				gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
-				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
-				gGL.vertex2i(local_rect.mRight, local_rect.mTop);
-				gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
-
-				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
-				gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
-				gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
-				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
-				gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
-				gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
-
-				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
-				gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
-				gGL.vertex2i(local_rect.mRight, local_rect.mTop);
-				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
-				gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
-				gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
-
-
-				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
-				gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
-				gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
-				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
-				gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
-				gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
-			}
-			gGL.end();
-		}
-	}
-
-	if (gFocusMgr.childHasMouseCapture(getDragHandle()))
-	{
-		mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLSmoothInterpolation::getInterpolant(CONTEXT_FADE_TIME));
-	}
-	else
-	{
-		mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(CONTEXT_FADE_TIME));
-	}
+	// draw cone of context pointing back to texture swatch	
+    LLRect local_rect = getLocalRect();
+    drawFrustum(local_rect, this, getDragHandle(), hasFocus());
 
 	updateImageStats();
 
diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h
index b2a34a37c4..c962cf98a2 100644
--- a/indra/newview/lltexturectrl.h
+++ b/indra/newview/lltexturectrl.h
@@ -29,6 +29,7 @@
 #define LL_LLTEXTURECTRL_H
 
 #include "llcoord.h"
+#include "lldrawfrustum.h"
 #include "llfiltereditor.h"
 #include "llfloater.h"
 #include "llfolderview.h"
@@ -249,7 +250,7 @@ typedef boost::function<void()> floater_close_callback;
 typedef boost::function<void(const LLUUID& asset_id)> set_image_asset_id_callback;
 typedef boost::function<void(LLPointer<LLViewerTexture> texture)> set_on_update_image_stats_callback;
 
-class LLFloaterTexturePicker : public LLFloater
+class LLFloaterTexturePicker : public LLFloater, public LLDrawFrustum
 {
 public:
 	LLFloaterTexturePicker(
@@ -291,7 +292,7 @@ public:
 	void			setActive(BOOL active);
 
 	LLView*			getOwner() const { return mOwner; }
-	void			setOwner(LLView* owner) { mOwner = owner; }
+	void			setOwner(LLView* owner) { mOwner = owner; setFrustumOrigin(owner); }
 	void			stopUsingPipette();
 	PermissionMask 	getFilterPermMask();
 
@@ -363,7 +364,6 @@ protected:
 	PermissionMask		mNonImmediateFilterPermMask;
 	BOOL				mCanApplyImmediately;
 	BOOL				mNoCopyTextureSelected;
-	F32					mContextConeOpacity;
 	LLSaveFolderState	mSavedFolderState;
 	BOOL				mSelectedItemPinned;
 
-- 
cgit v1.2.3


From 5213c4f1ec108f0a68e185bec85f2c77ded6bacf Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Tue, 1 Oct 2019 22:21:37 +0300
Subject: SL-6109 Cell selection support

---
 indra/llui/llscrolllistcell.cpp |  18 +----
 indra/llui/llscrolllistcell.h   |   8 +-
 indra/llui/llscrolllistctrl.cpp | 173 ++++++++++++++++++++++++++++++++--------
 indra/llui/llscrolllistctrl.h   |  17 +++-
 indra/llui/llscrolllistitem.cpp |  56 ++++++++++++-
 indra/llui/llscrolllistitem.h   |  21 ++++-
 6 files changed, 230 insertions(+), 63 deletions(-)

diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp
index d6627a6957..13839da400 100644
--- a/indra/llui/llscrolllistcell.cpp
+++ b/indra/llui/llscrolllistcell.cpp
@@ -172,7 +172,7 @@ U32 LLScrollListText::sCount = 0;
 
 LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p)
 :	LLScrollListCell(p),
-	mText(p.text.isProvided() ? p.text() : p.value().asString()),
+	mText(p.label.isProvided() ? p.label() : p.value().asString()),
 	mFont(p.font),
 	mColor(p.color),
 	mUseColor(p.color.isProvided()),
@@ -199,13 +199,6 @@ void LLScrollListText::highlightText(S32 offset, S32 num_chars)
 	mHighlightCount = llmax(0, num_chars);
 }
 
-//virtual
-void LLScrollListText::setHighlighted(bool highlighted)
-{
-    mHighlightOffset = 0;
-    mHighlightCount = highlighted ? -1 : 0;
-}
-
 //virtual 
 BOOL LLScrollListText::isText() const
 {
@@ -323,15 +316,6 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col
 				1);
 		mRoundedRectImage->draw(highlight_rect, highlight_color);
 	}
-	else if (mHighlightCount < 0)
-	{
-		// Highlight whole cell
-		LLRect highlight_rect(0,
-		getHeight(),
-		getWidth() - 1,
-		-1);
-		gl_rect_2d(highlight_rect, LLColor4(0.38f, 0.694f, 0.573f, 0.35f));
-	}
 
 	// Try to draw the entire string
 	F32 right_x;
diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h
index b4bb14bcf1..ef7f717b57 100644
--- a/indra/llui/llscrolllistcell.h
+++ b/indra/llui/llscrolllistcell.h
@@ -60,7 +60,7 @@ public:
 
 		Optional<void*>				userdata;
 		Optional<LLSD>				value; // state of checkbox, icon id/name, date
-		Optional<std::string>		text; // description or text
+		Optional<std::string>		label; // description or text
 		Optional<std::string>		tool_tip;
 
 		Optional<const LLFontGL*>	font;
@@ -70,12 +70,13 @@ public:
 		Optional<LLColor4>			color;
 
 		Params()
-		:	type("type", "text"),
+		:	type("cell_type", "text"), // Don't use "type", it overlaps with xml's parameter
 			column("column"),
 			width("width"),
 			enabled("enabled", true),
 			visible("visible", true),
 			value("value"),
+			label("label"),
 			tool_tip("tool_tip", ""),
 			font("font", LLFontGL::getFontSansSerifSmall()),
 			font_color("font_color", LLColor4::black),
@@ -103,7 +104,6 @@ public:
 	virtual BOOL			getVisible() const { return TRUE; }
 	virtual void			setWidth(S32 width) { mWidth = width; }
 	virtual void			highlightText(S32 offset, S32 num_chars) {}
-	virtual void			setHighlighted(bool highlighted) {}
 	virtual BOOL			isText() const { return FALSE; }
 	virtual BOOL			needsToolTip() const { return ! mToolTip.empty(); }
 	virtual void			setColor(const LLColor4&) {}
@@ -141,7 +141,6 @@ public:
 	/*virtual*/ const LLSD getValue() const;
 	/*virtual*/ BOOL	getVisible() const;
 	/*virtual*/ void	highlightText(S32 offset, S32 num_chars);
-	/*virtual*/ void	setHighlighted(bool highlighted);
 
 	/*virtual*/ void	setColor(const LLColor4&);
 	/*virtual*/ BOOL	isText() const;
@@ -160,6 +159,7 @@ protected:
 	S32				mTextWidth;
 	const LLFontGL*	mFont;
 	LLColor4		mColor;
+	LLColor4		mHighlightColor;
 	U8				mUseColor;
 	LLFontGL::HAlign mFontAlignment;
 	BOOL			mVisible;
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 7e17dd7c8d..94b130e28d 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -115,6 +115,13 @@ struct SortScrollListItem
 // LLScrollListCtrl
 //---------------------------------------------------------------------------
 
+void LLScrollListCtrl::SelectionTypeNames::declareValues()
+{
+    declare("row", LLScrollListCtrl::ROW);
+    declare("cell", LLScrollListCtrl::CELL);
+    declare("header", LLScrollListCtrl::HEADER);
+}
+
 LLScrollListCtrl::Contents::Contents()
 :	columns("column"),
 	rows("row")
@@ -128,6 +135,7 @@ LLScrollListCtrl::Params::Params()
 	has_border("draw_border"),
 	draw_heading("draw_heading"),
 	search_column("search_column", 0),
+	selection_type("selection_type", ROW),
 	sort_column("sort_column", -1),
 	sort_ascending("sort_ascending", true),
 	can_sort("can_sort", true),
@@ -164,6 +172,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
 	mCommitOnKeyboardMovement(p.commit_on_keyboard_movement),
 	mCommitOnSelectionChange(false),
 	mSelectionChanged(false),
+	mSelectionType(p.selection_type),
 	mNeedsScroll(false),
 	mCanSelect(true),
 	mCanSort(p.can_sort),
@@ -821,7 +830,15 @@ BOOL LLScrollListCtrl::selectFirstItem()
 		{
 			if (!itemp->getSelected())
 			{
-				selectItem(itemp);
+                switch (mSelectionType)
+                {
+                case CELL:
+                    selectItem(itemp, 0);
+                    break;
+                case HEADER:
+                case ROW:
+                    selectItem(itemp, -1);
+                }
 			}
 			success = TRUE;
 			mOriginalSelection = 0;
@@ -880,7 +897,8 @@ BOOL LLScrollListCtrl::selectItemRange( S32 first_index, S32 last_index )
 		{
 			if( itemp->getEnabled() )
 			{
-				selectItem(itemp, FALSE);
+				// TODO: support range selection for cells
+				selectItem(itemp, -1, FALSE);
 				success = TRUE;				
 			}
 		}
@@ -1006,10 +1024,14 @@ void LLScrollListCtrl::clearHighlightedItems()
 
 void LLScrollListCtrl::mouseOverHighlightNthItem(S32 target_index)
 {
-	if (mHighlightedItem != target_index)
-	{
-		mHighlightedItem = target_index;
-	}
+    if (mHighlightedItem != target_index)
+    {
+        if (mHighlightedItem >= 0 && mHighlightedItem < mItemList.size())
+        {
+            mItemList[mHighlightedItem]->setHoverCell(-1);
+        }
+        mHighlightedItem = target_index;
+    }
 }
 
 S32	LLScrollListCtrl::selectMultiple( uuid_vec_t ids )
@@ -1024,7 +1046,8 @@ S32	LLScrollListCtrl::selectMultiple( uuid_vec_t ids )
 		{
 			if (item->getEnabled() && (item->getUUID() == (*iditr)))
 			{
-				selectItem(item,FALSE);
+				// TODO: support multiple selection for cells
+				selectItem(item, -1, FALSE);
 				++count;
 				break;
 			}
@@ -1097,7 +1120,7 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection)
 			{
 				if (prev_item)
 				{
-					selectItem(prev_item, !extend_selection);
+					selectItem(prev_item, cur_item->getSelectedCell(), !extend_selection);
 				}
 				else
 				{
@@ -1141,7 +1164,7 @@ void LLScrollListCtrl::selectNextItem( BOOL extend_selection)
 			{
 				if (next_item)
 				{
-					selectItem(next_item, !extend_selection);
+					selectItem(next_item, cur_item->getSelectedCell(), !extend_selection);
 				}
 				else
 				{
@@ -1212,7 +1235,7 @@ BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sen
 	bool found = NULL != item;
 	if(found)
 	{
-		selectItem(item);
+		selectItem(item, -1);
 	}
 
 	if (mCommitOnSelectionChange)
@@ -1280,7 +1303,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
 			BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE;
 			if (select)
 			{
-				selectItem(item);
+				selectItem(item, -1);
 				found = TRUE;
 				break;
 			}
@@ -1320,7 +1343,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
 				// find offset of matching text (might have leading whitespace)
 				S32 offset = item_label.find(target_trimmed);
 				cellp->highlightText(offset, target_trimmed.size());
-				selectItem(item);
+				selectItem(item, -1);
 				found = TRUE;
 				break;
 			}
@@ -1386,7 +1409,7 @@ BOOL LLScrollListCtrl::setSelectedByValue(const LLSD& value, BOOL selected)
 		{
 			if (selected)
 			{
-				selectItem(item);
+				selectItem(item, -1);
 			}
 			else
 			{
@@ -1466,7 +1489,7 @@ void LLScrollListCtrl::drawItems()
 		
 		S32 max_columns = 0;
 
-		LLColor4 highlight_color = LLColor4::white;
+		LLColor4 highlight_color = LLColor4::white; // ex: text inside cells
 		static LLUICachedControl<F32> type_ahead_timeout ("TypeAheadTimeout", 0);
 		highlight_color.mV[VALPHA] = clamp_rescale(mSearchTimer.getElapsedTimeF32(), type_ahead_timeout * 0.7f, type_ahead_timeout(), 0.4f, 0.f);
 
@@ -1492,7 +1515,8 @@ void LLScrollListCtrl::drawItems()
 			max_columns = llmax(max_columns, item->getNumColumns());
 
 			LLColor4 fg_color;
-			LLColor4 bg_color(LLColor4::transparent);
+			LLColor4 hover_color(LLColor4::transparent);
+			LLColor4 select_color(LLColor4::transparent);
 
 			if( mScrollLines <= line && line < mScrollLines + num_page_lines )
 			{
@@ -1501,44 +1525,44 @@ void LLScrollListCtrl::drawItems()
 				{
 					if(item->getHighlighted())	// if it's highlighted, average the colors
 					{
-						bg_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f);
+						select_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f);
 					}
 					else						// otherwise just select-highlight it
 					{
-						bg_color = mBgSelectedColor.get();
+						select_color = mBgSelectedColor.get();
 					}
 
 					fg_color = (item->getEnabled() ? mFgSelectedColor.get() : mFgDisabledColor.get());
 				}
-				else if (mHighlightedItem == line && mCanSelect)
+				if (mHighlightedItem == line && mCanSelect)
 				{
 					if(item->getHighlighted())	// if it's highlighted, average the colors
 					{
-						bg_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f);
+						hover_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f);
 					}
 					else						// otherwise just hover-highlight it
 					{
-						bg_color = mHoveredColor.get();
+						hover_color = mHoveredColor.get();
 					}
 				}
 				else if (item->getHighlighted())
 				{
-					bg_color = mHighlightedColor.get();
+					hover_color = mHighlightedColor.get();
 				}
 				else 
 				{
 					if (mDrawStripes && (line % 2 == 0) && (max_columns > 1))
 					{
-						bg_color = mBgStripeColor.get();
+						hover_color = mBgStripeColor.get();
 					}
 				}
 
 				if (!item->getEnabled())
 				{
-					bg_color = mBgReadOnlyColor.get();
+					hover_color = mBgReadOnlyColor.get();
 				}
 
-				item->draw(item_rect, fg_color % alpha, bg_color% alpha, highlight_color % alpha, mColumnPadding);
+				item->draw(item_rect, fg_color % alpha, hover_color% alpha, select_color% alpha, highlight_color % alpha, mColumnPadding);
 
 				cur_y -= mLineHeight;
 			}
@@ -1690,7 +1714,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
 			{
 				if (mLastSelected == NULL)
 				{
-					selectItem(hit_item);
+					selectItem(hit_item, getColumnIndexFromOffset(x));
 				}
 				else
 				{
@@ -1714,7 +1738,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
 						LLScrollListItem *item = *itor;
                         if (item == hit_item || item == lastSelected)
 						{
-							selectItem(item, FALSE);
+							selectItem(item, getColumnIndexFromOffset(x), FALSE);
 							selecting = !selecting;
 							if (hit_item == lastSelected)
 							{
@@ -1724,7 +1748,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
 						}
 						if (selecting)
 						{
-							selectItem(item, FALSE);
+							selectItem(item, getColumnIndexFromOffset(x), FALSE);
 						}
 					}
 				}
@@ -1739,7 +1763,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
 				{
 					if(!(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable))
 					{
-						selectItem(hit_item, FALSE);
+						selectItem(hit_item, getColumnIndexFromOffset(x), FALSE);
 					}
 					else
 					{
@@ -1753,12 +1777,12 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
 			else
 			{
 				deselectAllItems(TRUE);
-				selectItem(hit_item);
+				selectItem(hit_item, getColumnIndexFromOffset(x));
 			}
 		}
 		else
 		{
-			selectItem(hit_item);
+			selectItem(hit_item, getColumnIndexFromOffset(x));
 		}
 
 		selection_changed = mSelectionChanged;
@@ -2126,8 +2150,29 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
 	{
 		LLScrollListItem* item = hitItem(x, y);
 		if (item)
-		{
-			mouseOverHighlightNthItem(getItemIndex(item));
+        {
+            mouseOverHighlightNthItem(getItemIndex(item));
+            switch (mSelectionType)
+            {
+            case CELL:
+                item->setHoverCell(getColumnIndexFromOffset(x));
+                break;
+            case HEADER:
+                {
+                    S32 cell = getColumnIndexFromOffset(x);
+                    if (cell > 0)
+                    {
+                        item->setHoverCell(cell);
+                    }
+                    else
+                    {
+                        item->setHoverCell(-1);
+                    }
+                    break;
+                }
+            case ROW:
+                break;
+            }
 		}
 		else
 		{
@@ -2175,6 +2220,52 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask )
 					handled = TRUE;
 				}
 				break;
+            case KEY_LEFT:
+                if (mAllowKeyboardMovement || hasFocus())
+                {
+                    // TODO: support multi-select
+                    LLScrollListItem *item = getFirstSelected();
+                    S32 cell = item->getSelectedCell();
+                    switch (mSelectionType)
+                    {
+                    case CELL:
+                        if (cell < mColumns.size()) cell++;
+                        break;
+                    case HEADER:
+                        if (cell == -1) cell = 1;
+                        else if (cell > 1 && cell < mColumns.size()) cell++; // skip header
+                        break;
+                    case ROW:
+                        cell = -1;
+                        break;
+                    }
+                    item->setSelectedCell(cell);
+                    handled = TRUE;
+                }
+                break;
+            case KEY_RIGHT:
+                if (mAllowKeyboardMovement || hasFocus())
+                {
+                    // TODO: support multi-select
+                    LLScrollListItem *item = getFirstSelected();
+                    S32 cell = item->getSelectedCell();
+                    switch (mSelectionType)
+                    {
+                    case CELL:
+                        if (cell >= 0) cell--;
+                        break;
+                    case HEADER:
+                        if (cell > 1) cell--;
+                        else if (cell == 1) cell = -1; // skip header
+                        break;
+                    case ROW:
+                        cell = -1;
+                        break;
+                    }
+                    item->setSelectedCell(cell);
+                    handled = TRUE;
+                }
+                break;
 			case KEY_PAGE_UP:
 				if (mAllowKeyboardMovement || hasFocus())
 				{
@@ -2343,7 +2434,7 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char)
 				LLWString item_label = utf8str_to_wstring(cellp->getValue().asString());
 				if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char)
 				{
-					selectItem(item);
+					selectItem(item, -1);
 					mNeedsScroll = true;
 					cellp->highlightText(0, 1);
 					mSearchTimer.reset();
@@ -2395,7 +2486,7 @@ BOOL LLScrollListCtrl::isRepeatedChars(const LLWString& string) const
 	return TRUE;
 }
 
-void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, BOOL select_single_item)
+void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, S32 cell, BOOL select_single_item)
 {
 	if (!itemp) return;
 
@@ -2414,6 +2505,18 @@ void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, BOOL select_single_it
 			deselectAllItems(TRUE);
 		}
 		itemp->setSelected(TRUE);
+        switch (mSelectionType)
+        {
+        case CELL:
+            itemp->setSelectedCell(cell);
+            break;
+        case HEADER:
+            itemp->setSelectedCell(cell <= 0 ? -1 : cell);
+            break;
+        case ROW:
+            itemp->setSelectedCell(-1);
+            break;
+        }
 		mLastSelected = itemp;
 		mSelectionChanged = true;
 	}
@@ -2674,7 +2777,7 @@ void	LLScrollListCtrl::selectAll()
 		LLScrollListItem *itemp = *iter;
 		if( itemp->getEnabled() )
 		{
-			selectItem(itemp, FALSE);
+			selectItem(itemp, -1, FALSE);
 		}
 	}
 
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index 249d9a6f15..bf1055c8dc 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -54,6 +54,18 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	public LLCtrlListInterface, public LLCtrlScrollInterface
 {
 public:
+    typedef enum e_selection_type
+    {
+        ROW, // default
+        CELL, // does not support multi-selection
+        HEADER, // when pointing to cells in column 0 will highlight whole row, otherwise cell, no multi-select
+    } ESelectionType;
+
+    struct SelectionTypeNames : public LLInitParam::TypeValuesHelper<LLScrollListCtrl::ESelectionType, SelectionTypeNames>
+    {
+        static void declareValues();
+    };
+
 	struct Contents : public LLInitParam::Block<Contents>
 	{
 		Multiple<LLScrollListColumn::Params>	columns;
@@ -99,6 +111,8 @@ public:
 						commit_on_keyboard_movement,
 						mouse_wheel_opaque;
 
+		Optional<ESelectionType, SelectionTypeNames> selection_type;
+
 		// display flags
 		Optional<bool>	has_border,
 						draw_heading,
@@ -430,7 +444,7 @@ private:
 	void            updateLineHeightInsert(LLScrollListItem* item);
 	void			reportInvalidInput();
 	BOOL			isRepeatedChars(const LLWString& string) const;
-	void			selectItem(LLScrollListItem* itemp, BOOL single_select = TRUE);
+	void			selectItem(LLScrollListItem* itemp, S32 cell, BOOL single_select = TRUE);
 	void			deselectItem(LLScrollListItem* itemp);
 	void			commitIfChanged();
 	BOOL			setSort(S32 column, BOOL ascending);
@@ -455,6 +469,7 @@ private:
 	bool			mCommitOnKeyboardMovement;
 	bool			mCommitOnSelectionChange;
 	bool			mSelectionChanged;
+	ESelectionType	mSelectionType;
 	bool			mNeedsScroll;
 	bool			mMouseWheelOpaque;
 	bool			mCanSelect;
diff --git a/indra/llui/llscrolllistitem.cpp b/indra/llui/llscrolllistitem.cpp
index df22c88afb..51c615dd00 100644
--- a/indra/llui/llscrolllistitem.cpp
+++ b/indra/llui/llscrolllistitem.cpp
@@ -40,6 +40,8 @@
 LLScrollListItem::LLScrollListItem( const Params& p )
 :	mSelected(FALSE),
 	mHighlighted(FALSE),
+	mHoverIndex(-1),
+	mSelectedIndex(-1),
 	mEnabled(p.enabled),
 	mUserdata(p.userdata),
 	mItemValue(p.value)
@@ -53,6 +55,28 @@ LLScrollListItem::~LLScrollListItem()
 	mColumns.clear();
 }
 
+void LLScrollListItem::setSelected(BOOL b)
+{
+    mSelected = b;
+    mSelectedIndex = -1;
+}
+
+void LLScrollListItem::setHighlighted(BOOL b)
+{
+    mHighlighted = b;
+    mHoverIndex = -1;
+}
+
+void LLScrollListItem::setHoverCell(S32 cell)
+{
+    mHoverIndex = cell;
+}
+
+void LLScrollListItem::setSelectedCell(S32 cell)
+{
+    mSelectedIndex = cell;
+}
+
 void LLScrollListItem::addColumn(const LLScrollListCell::Params& p)
 {
 	mColumns.push_back(LLScrollListCell::create(p));
@@ -120,12 +144,21 @@ std::string LLScrollListItem::getContentsCSV() const
 }
 
 
-void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding)
+void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& hover_color, const LLColor4& select_color, const LLColor4& highlight_color, S32 column_padding)
 {
 	// draw background rect
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	LLRect bg_rect = rect;
-	gl_rect_2d( bg_rect, bg_color );
+    if (mSelectedIndex < 0 && getSelected())
+    {
+        // Whole item is highlighted/selected
+        gl_rect_2d(bg_rect, select_color);
+    }
+    else if (mHoverIndex < 0)
+    {
+        // Whole item is highlighted/selected
+        gl_rect_2d(bg_rect, hover_color);
+    }
 
 	S32 cur_x = rect.mLeft;
 	S32 num_cols = getNumColumns();
@@ -141,6 +174,25 @@ void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const
 		{
 			LLUI::translate((F32) cur_x, (F32) rect.mBottom);
 
+            if (mSelectedIndex == cur_col)
+            {
+                // select specific cell
+                LLRect highlight_rect(0,
+                    cell->getHeight(),
+                    cell->getWidth(),
+                    0);
+                gl_rect_2d(highlight_rect, select_color);
+            }
+            else if (mHoverIndex == cur_col)
+            {
+                // highlight specific cell
+                LLRect highlight_rect(0,
+                    cell->getHeight(),
+                    cell->getWidth() ,
+                    0);
+                gl_rect_2d(highlight_rect, hover_color);
+            }
+
 			cell->draw( fg_color, highlight_color );
 		}
 		LLUI::popMatrix();
diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h
index 13655b5873..d2c3dd7721 100644
--- a/indra/llui/llscrolllistitem.h
+++ b/indra/llui/llscrolllistitem.h
@@ -77,15 +77,21 @@ public:
 
 	virtual ~LLScrollListItem();
 
-	void	setSelected( BOOL b )			{ mSelected = b; }
+	void	setSelected( BOOL b );
 	BOOL	getSelected() const				{ return mSelected; }
 
 	void	setEnabled( BOOL b )			{ mEnabled = b; }
 	BOOL	getEnabled() const 				{ return mEnabled; }
 
-	void	setHighlighted( BOOL b )		{ mHighlighted = b; }
+	void	setHighlighted( BOOL b );
 	BOOL	getHighlighted() const			{ return mHighlighted; }
 
+	void	setSelectedCell( S32 cell );
+	S32		getSelectedCell() const			{ return mSelectedIndex; }
+
+	void	setHoverCell( S32 cell );
+	S32		getHoverCell() const			{ return mHoverIndex; }
+
 	void	setUserdata( void* userdata )	{ mUserdata = userdata; }
 	void*	getUserdata() const 			{ return mUserdata; }
 
@@ -107,14 +113,21 @@ public:
 
 	std::string getContentsCSV() const;
 
-	virtual void draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding);
+	virtual void draw(const LLRect& rect,
+					  const LLColor4& fg_color,
+					  const LLColor4& hover_color, // highlight/hover selection of whole item or cell
+					  const LLColor4& select_color, // highlight/hover selection of whole item or cell
+					  const LLColor4& highlight_color, // highlights contents of cells (ex: text)
+					  S32 column_padding);
 
 protected:
 	LLScrollListItem( const Params& );
 
 private:
 	BOOL	mSelected;
-	BOOL	mHighlighted;
+    BOOL	mHighlighted;
+    S32		mHoverIndex;
+	S32		mSelectedIndex;
 	BOOL	mEnabled;
 	void*	mUserdata;
 	LLSD	mItemValue;
-- 
cgit v1.2.3


From fc03a5679e34a35f3e4773198b52cac1bd6be0b7 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Tue, 1 Oct 2019 22:23:49 +0300
Subject: SL-6109 Better hover and docking of keybinder

---
 indra/newview/llfloaterpreference.cpp              | 131 ++++++++-------------
 indra/newview/llfloaterpreference.h                |   3 -
 .../default/xui/en/panel_preferences_controls.xml  |  10 +-
 3 files changed, 51 insertions(+), 93 deletions(-)

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 088a0820aa..16f2426d1b 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -43,6 +43,7 @@
 #include "llcombobox.h"
 #include "llcommandhandler.h"
 #include "lldirpicker.h"
+#include "lldrawfrustum.h"
 #include "lleventtimer.h"
 #include "llfeaturemanager.h"
 #include "llfocusmgr.h"
@@ -169,14 +170,15 @@ static const U32 ALLOW_MASKS = 16;
 static const U32 CAN_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 | CAN_IGNORE_MASKS;
 
-class LLSetKeyBindDialog : public LLModalDialog
+class LLSetKeyBindDialog : public LLModalDialog, public LLDrawFrustum
 {
 public:
 	LLSetKeyBindDialog(const LLSD& key);
 	~LLSetKeyBindDialog();
 
 	/*virtual*/ BOOL postBuild();
-	/*virtual*/ void onClose(bool app_quiting);
+    /*virtual*/ void onClose(bool app_quiting);
+    /*virtual*/ void draw();
 
 	void setParent(LLPanelPreferenceControls* parent, U32 key_mask = DEFAULT_KEY_FILTER);
 
@@ -271,9 +273,18 @@ void LLSetKeyBindDialog::onClose(bool app_quiting)
     LLModalDialog::onClose(app_quiting);
 }
 
+//virtual
+void LLSetKeyBindDialog::draw()
+{
+    LLRect local_rect;
+    drawFrustum(local_rect, this, (LLView*)getDragHandle(), hasFocus());
+    LLModalDialog::draw();
+}
+
 void LLSetKeyBindDialog::setParent(LLPanelPreferenceControls* parent, U32 key_mask)
 {
     pParent = parent;
+    setFrustumOrigin(parent);
     mKeyFilterMask = key_mask;
 
     LLTextBase *text_ctrl = getChild<LLTextBase>("descritption");
@@ -3104,9 +3115,7 @@ static const controls_to_icon_t commands_and_headers =
 LLPanelPreferenceControls::LLPanelPreferenceControls()
     :LLPanelPreference(),
     mEditingColumn(-1),
-    mEditingMode(0),
-    mShowKeyDialog(false),
-    mHighlightedCell(NULL)
+    mEditingMode(0)
 {
     for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
     {
@@ -3135,41 +3144,6 @@ BOOL LLPanelPreferenceControls::postBuild()
     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)
-    {
-        mShowKeyDialog = false;
-        if (!mEditingControl.empty()
-            && mConflictHandler[mEditingMode].canAssignControl(mEditingControl))
-        {
-            LLScrollListItem* item = pControlsTable->getFirstSelected(); // don't use pControlsTable->hitItem(x, y) dur to drift;
-            if (item)
-            {
-                mEditingColumn = pControlsTable->getColumnIndexFromOffset(x);
-                if (mEditingColumn > 0)
-                {
-                    LLScrollListCell* cell = item->getColumn(mEditingColumn);
-                    if (cell)
-                    {
-                        LLSetKeyBindDialog* dialog = LLFloaterReg::showTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD(), TRUE);
-                        if (dialog)
-                        {
-                            dialog->setParent(this, DEFAULT_KEY_FILTER);
-                            cell->setHighlighted(true);
-                            mHighlightedCell = cell;
-                            pControlsTable->deselectAllItems();
-                            return TRUE;
-                        }
-                    }
-                }
-            }
-        }
-    }
-    return LLPanelPreference::handleHover(x, y, mask);
-}
-
 void LLPanelPreferenceControls::addGroupRow(const std::string &control_name, const std::string &icon)
 {
     LLScrollListItem::Params item_params;
@@ -3221,13 +3195,7 @@ void LLPanelPreferenceControls::regenerateControls()
 void LLPanelPreferenceControls::populateControlTable()
 {
     pControlsTable->clearRows();
-
-    if (mHighlightedCell)
-    {
-        mHighlightedCell->setHighlighted(false);
-        mHighlightedCell = NULL;
-    }
-
+    
     // todo: subsections need sorting?
     std::string label, control_name;
     LLScrollListCell::Params cell_params;
@@ -3294,6 +3262,7 @@ void LLPanelPreferenceControls::addSeparator()
 
 void LLPanelPreferenceControls::updateTable()
 {
+    pControlsTable->deselectAllItems();
     mEditingControl.clear();
     std::vector<LLScrollListItem*> list = pControlsTable->getAllData();
     for (S32 i = 0; i < list.size(); ++i)
@@ -3309,12 +3278,6 @@ void LLPanelPreferenceControls::updateTable()
             cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 2));
         }
     }
-
-    if (mHighlightedCell)
-    {
-        mHighlightedCell->setHighlighted(false);
-        mHighlightedCell = NULL;
-    }
 }
 
 void LLPanelPreferenceControls::apply()
@@ -3326,11 +3289,6 @@ void LLPanelPreferenceControls::apply()
             mConflictHandler[i].saveToSettings();
         }
     }
-    if (mHighlightedCell)
-    {
-        mHighlightedCell->setHighlighted(false);
-        mHighlightedCell = NULL;
-    }
 }
 
 void LLPanelPreferenceControls::cancel()
@@ -3343,11 +3301,6 @@ void LLPanelPreferenceControls::cancel()
         }
     }
     pControlsTable->clear();
-    if (mHighlightedCell)
-    {
-        mHighlightedCell->setHighlighted(false);
-        mHighlightedCell = NULL;
-    }
 }
 
 void LLPanelPreferenceControls::saveSettings()
@@ -3366,11 +3319,6 @@ void LLPanelPreferenceControls::saveSettings()
     {
         regenerateControls();
     }
-    else if (mHighlightedCell)
-    {
-        mHighlightedCell->setHighlighted(false);
-        mHighlightedCell = NULL;
-    }
 }
 
 void LLPanelPreferenceControls::resetDirtyChilds()
@@ -3380,7 +3328,6 @@ void LLPanelPreferenceControls::resetDirtyChilds()
 
 void LLPanelPreferenceControls::onListCommit()
 {
-    mShowKeyDialog = false;
     LLScrollListItem* item = pControlsTable->getFirstSelected();
     if (item == NULL)
     {
@@ -3391,11 +3338,20 @@ void LLPanelPreferenceControls::onListCommit()
 
     if (control.empty())
     {
+        pControlsTable->deselectAllItems();
         return;
     }
 
     if (!mConflictHandler[mEditingMode].canAssignControl(control))
     {
+        pControlsTable->deselectAllItems();
+        return;
+    }
+
+    S32 cell_ind = item->getSelectedCell();
+    if (cell_ind <= 0)
+    {
+        pControlsTable->deselectAllItems();
         return;
     }
 
@@ -3403,13 +3359,27 @@ void LLPanelPreferenceControls::onListCommit()
     // 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
-    mEditingControl = control;
-    mShowKeyDialog = true;
 
-    if (mHighlightedCell)
+    LLScrollListCell* cell = item->getColumn(cell_ind);
+    if (cell)
+    {
+        LLSetKeyBindDialog* dialog = LLFloaterReg::getTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD());
+        if (dialog)
+        {
+            mEditingControl = control;
+            mEditingColumn = cell_ind;
+            dialog->setParent(this, DEFAULT_KEY_FILTER);
+
+            LLFloater* root_floater = gFloaterView->getParentFloater(this);
+            if (root_floater)
+                root_floater->addDependentFloater(dialog);
+            dialog->openFloater();
+            dialog->setFocus(TRUE);
+        }
+    }
+    else
     {
-        mHighlightedCell->setHighlighted(false);
-        mHighlightedCell = NULL;
+        pControlsTable->deselectAllItems();
     }
 }
 
@@ -3426,8 +3396,6 @@ void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MAS
         return;
     }
 
-    pControlsTable->deselectAllItems();
-    pControlsTable->selectByValue(mEditingControl);
     if ( mEditingColumn > 0)
     {
         mConflictHandler[mEditingMode].registerControl(mEditingControl, mEditingColumn - 1, click, key, mask, ignore_mask);
@@ -3450,10 +3418,7 @@ void LLPanelPreferenceControls::onDefaultKeyBind()
     {
         return;
     }
-
-    pControlsTable->deselectAllItems();
-    pControlsTable->selectByValue(mEditingControl);
-
+    
     if (mEditingColumn > 0)
     {
         mConflictHandler[mEditingMode].resetToDefault(mEditingControl, mEditingColumn - 1);
@@ -3463,11 +3428,7 @@ void LLPanelPreferenceControls::onDefaultKeyBind()
 
 void LLPanelPreferenceControls::onCancelKeyBind()
 {
-    if (mHighlightedCell)
-    {
-        mHighlightedCell->setHighlighted(false);
-        mHighlightedCell = NULL;
-    }
+    pControlsTable->deselectAllItems();
 }
 
 LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const LLSD& key)
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 2fe3b98abd..9100a91356 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -302,7 +302,6 @@ public:
 	~LLPanelPreferenceControls();
 
 	BOOL postBuild();
-	BOOL handleHover(S32 x, S32 y, MASK mask);
 
 	void apply();
 	void cancel();
@@ -325,12 +324,10 @@ private:
 
 	LLScrollListCtrl* pControlsTable;
 	LLComboBox *pKeyModeBox;
-	LLScrollListCell *mHighlightedCell;
 	LLKeyConflictHandler mConflictHandler[LLKeyConflictHandler::MODE_COUNT];
 	std::string mEditingControl;
 	S32 mEditingColumn;
 	S32 mEditingMode;
-	bool mShowKeyDialog;
 };
 
 class LLFloaterPreferenceGraphicsAdvanced : public LLFloater
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
index 385d4796a0..b7b5280825 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
@@ -255,14 +255,14 @@
    height="23"
    width="110"
    name="key_mode">
-    <combo_box.item
-     label="First Person "
-     name="first_person"
-     value="0"/>
     <combo_box.item
      label="Third Person "
      name="third_person"
      value="1"/>
+    <combo_box.item
+     label="First Person "
+     name="first_person"
+     value="0"/>
     <combo_box.item
      label="Edit"
      name="edit"
@@ -292,13 +292,13 @@
    follows="all"
    layout="topleft"
    column_padding="0"
+   selection_type="header"
    top="31"
    left="3"
    bottom="-3"
    right="-3"
    can_sort="false"
    multi_select="false"
-   bg_selected_color="Transparent"
    name="controls_list">
     <scroll_list.columns
      relative_width="0.34"
-- 
cgit v1.2.3


From b6890180eae59529a5825a47f80c9833c0959352 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Wed, 2 Oct 2019 20:51:47 +0300
Subject: SL-6109 Removed obsolete control, moved table init to xml, cleanup

---
 indra/newview/app_settings/settings.xml            |   8 +-
 indra/newview/llfloaterpreference.cpp              | 245 ++-------
 indra/newview/llfloaterpreference.h                |  10 -
 indra/newview/llkeyconflict.cpp                    |  13 +-
 indra/newview/llkeyconflict.h                      |   2 +-
 indra/newview/lltoolpie.h                          |   1 -
 .../default/xui/en/control_table_contents.xml      | 569 +++++++++++++++++++++
 .../default/xui/en/panel_preferences_controls.xml  | 258 +---------
 .../default/xui/en/panel_preferences_move.xml      |  64 ---
 .../default/xui/en/panel_preferences_sound.xml     |  26 +-
 10 files changed, 636 insertions(+), 560 deletions(-)
 create mode 100644 indra/newview/skins/default/xui/en/control_table_contents.xml

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 15447e7e83..bbac65ef61 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -3494,7 +3494,7 @@
     <key>DoubleClickAutoPilot</key>
     <map>
       <key>Comment</key>
-      <string>Enable double-click auto pilot</string>
+      <string>(Obsolete)Enable double-click auto pilot</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -3505,13 +3505,13 @@
     <key>DoubleClickTeleport</key>
     <map>
       <key>Comment</key>
-      <string>Enable double-click to teleport where allowed</string>
+      <string>Enable double-click to teleport where allowed (afects minimap and people panel)</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>0</integer>
+      <integer>1</integer>
     </map>
     <key>DoubleClickShowWorldMap</key>
     <map>
@@ -15364,7 +15364,7 @@
     <key>ClickToWalk</key>
     <map>
       <key>Comment</key>
-      <string>Click in world to walk to location</string>
+      <string>(obsolete)Click in world to walk to location</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 16f2426d1b..2354be25e9 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -564,8 +564,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
 	mGotPersonalInfo(false),
 	mOriginalIMViaEmail(false),
 	mLanguageChanged(false),
-	mAvatarDataInitialized(false),
-	mClickActionDirty(false)
+	mAvatarDataInitialized(false)
 {
 	LLConversationLog::instance().addObserver(this);
 
@@ -587,7 +586,6 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
 	mCommitCallbackRegistrar.add("Pref.ResetCache",				boost::bind(&LLFloaterPreference::onClickResetCache, this));
 	mCommitCallbackRegistrar.add("Pref.ClickSkin",				boost::bind(&LLFloaterPreference::onClickSkin, this,_1, _2));
 	mCommitCallbackRegistrar.add("Pref.SelectSkin",				boost::bind(&LLFloaterPreference::onSelectSkin, this));
-	mCommitCallbackRegistrar.add("Pref.VoiceSetKey",			boost::bind(&LLFloaterPreference::onClickSetKey, this));
 	mCommitCallbackRegistrar.add("Pref.VoiceSetMiddleMouse",	boost::bind(&LLFloaterPreference::onClickSetMiddleMouse, this));
 	mCommitCallbackRegistrar.add("Pref.SetSounds",				boost::bind(&LLFloaterPreference::onClickSetSounds, this));
 	mCommitCallbackRegistrar.add("Pref.ClickEnablePopup",		boost::bind(&LLFloaterPreference::onClickEnablePopup, this));
@@ -615,8 +613,6 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
 
 	sSkin = gSavedSettings.getString("SkinCurrent");
 
-	mCommitCallbackRegistrar.add("Pref.ClickActionChange",		boost::bind(&LLFloaterPreference::onClickActionChange, this));
-
 	gSavedSettings.getControl("NameTagShowUsernames")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged,  _2));	
 	gSavedSettings.getControl("NameTagShowFriends")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged,  _2));	
 	gSavedSettings.getControl("UseDisplayNames")->getCommitSignal()->connect(boost::bind(&handleDisplayNamesOptionChanged,  _2));
@@ -883,12 +879,6 @@ void LLFloaterPreference::apply()
 	}
 
 	saveAvatarProperties();
-
-	if (mClickActionDirty)
-	{
-		updateClickActionSettings();
-		mClickActionDirty = false;
-	}
 }
 
 void LLFloaterPreference::cancel()
@@ -921,12 +911,6 @@ void LLFloaterPreference::cancel()
 	// reverts any changes to current skin
 	gSavedSettings.setString("SkinCurrent", sSkin);
 
-	if (mClickActionDirty)
-	{
-		updateClickActionControls();
-		mClickActionDirty = false;
-	}
-
 	LLFloaterPreferenceProxy * advanced_proxy_settings = LLFloaterReg::findTypedInstance<LLFloaterPreferenceProxy>("prefs_proxy");
 	if (advanced_proxy_settings)
 	{
@@ -1008,9 +992,6 @@ void LLFloaterPreference::onOpen(const LLSD& key)
 	onChangeTextureFolder();
 	onChangeSoundFolder();
 	onChangeAnimationFolder();
-
-	// Load (double-)click to walk/teleport settings.
-	updateClickActionControls();
 	
 	// Enabled/disabled popups, might have been changed by user actions
 	// while preferences floater was closed.
@@ -1891,10 +1872,6 @@ void LLFloaterPreference::onChangeQuality(const LLSD& data)
 	refresh();
 }
 
-void LLFloaterPreference::onClickSetKey()
-{
-}
-
 void LLFloaterPreference::onClickSetMiddleMouse()
 {
 	LLUICtrl* p2t_line_editor = getChild<LLUICtrl>("modifier_combo");
@@ -2378,11 +2355,6 @@ void LLFloaterPreference::onClickAdvanced()
 	}
 }
 
-void LLFloaterPreference::onClickActionChange()
-{
-	mClickActionDirty = true;
-}
-
 void LLFloaterPreference::onClickPermsDefault()
 {
 	LLFloaterReg::showInstance("perms_default");
@@ -2420,26 +2392,6 @@ void LLFloaterPreference::onLogChatHistorySaved()
 	}
 }
 
-void LLFloaterPreference::updateClickActionSettings()
-{
-	const int single_clk_action = getChild<LLComboBox>("single_click_action_combo")->getValue().asInteger();
-	const int double_clk_action = getChild<LLComboBox>("double_click_action_combo")->getValue().asInteger();
-
-	gSavedSettings.setBOOL("ClickToWalk",			single_clk_action == 1);
-	gSavedSettings.setBOOL("DoubleClickAutoPilot",	double_clk_action == 1);
-	gSavedSettings.setBOOL("DoubleClickTeleport",	double_clk_action == 2);
-}
-
-void LLFloaterPreference::updateClickActionControls()
-{
-	const bool click_to_walk = gSavedSettings.getBOOL("ClickToWalk");
-	const bool dbl_click_to_walk = gSavedSettings.getBOOL("DoubleClickAutoPilot");
-	const bool dbl_click_to_teleport = gSavedSettings.getBOOL("DoubleClickTeleport");
-
-	getChild<LLComboBox>("single_click_action_combo")->setValue((int)click_to_walk);
-	getChild<LLComboBox>("double_click_action_combo")->setValue(dbl_click_to_teleport ? 2 : (int)dbl_click_to_walk);
-}
-
 void LLFloaterPreference::applyUIColor(LLUICtrl* ctrl, const LLSD& param)
 {
 	LLUIColorTable::instance().setColor(param.asString(), LLColor4(ctrl->getValue()));
@@ -3048,70 +3000,6 @@ void LLPanelPreferenceGraphics::setHardwareDefaults()
 //------------------------LLPanelPreferenceControls--------------------------------
 static LLPanelInjector<LLPanelPreferenceControls> t_pref_contrls("panel_preference_controls");
 
-//name of control and name of icon if it is a group, likely 'TEMP' until xml gets properly populated
-typedef std::vector<std::pair<std::string, std::string> > controls_to_icon_t;
-static const controls_to_icon_t commands_and_headers =
-{
-    //{ "control_view_actions", "Search_Icon" },
-    //{ "control_interactions", "Command_Gestures_Icon" },
-    { "control_movements", "Move_Walk_Off" },
-    { "walk_to", "" },
-    { "teleport_to", "" },
-    { "push_forward", "" },
-    { "push_backward", "" },
-    { "turn_left", "" },
-    { "turn_right", "" },
-    { "slide_left", "" },
-    { "slide_right", "" },
-    { "jump", "" },
-    { "push_down", "" },
-    { "run_forward", "" },
-    { "run_backward", "" },
-    { "run_left", "" },
-    { "run_right", "" },
-    { "toggle_run", "" },
-    { "toggle_fly", "" },
-    { "toggle_sit", "" },
-    { "stop_moving", "" },
-    { "control_camera", "Cam_FreeCam_Off" },
-    { "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", "Tool_Dozer" },
-    { "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", "Audio_Press" },
-    { "toggle_pause_media", "" },
-    { "toggle_enable_media", "" },
-    { "voice_follow_key", "" },
-    { "toggle_voice", "" },
-    { "start_chat", "" },
-    { "start_gesture", "" },
-};
-
 LLPanelPreferenceControls::LLPanelPreferenceControls()
     :LLPanelPreference(),
     mEditingColumn(-1),
@@ -3129,10 +3017,6 @@ LLPanelPreferenceControls::~LLPanelPreferenceControls()
 
 BOOL LLPanelPreferenceControls::postBuild()
 {
-    //todo: add pitch/yaw?
-    //todo: should be auto-expandable with menu items and should pull names from menu when possible
-
-
     // populate list of controls
     pControlsTable = getChild<LLScrollListCtrl>("controls_list");
     pKeyModeBox = getChild<LLComboBox>("key_mode");
@@ -3144,47 +3028,6 @@ BOOL LLPanelPreferenceControls::postBuild()
     return TRUE;
 }
 
-void LLPanelPreferenceControls::addGroupRow(const std::string &control_name, const std::string &icon)
-{
-    LLScrollListItem::Params item_params;
-    item_params.value = "";
-
-    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 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();
@@ -3195,58 +3038,74 @@ void LLPanelPreferenceControls::regenerateControls()
 void LLPanelPreferenceControls::populateControlTable()
 {
     pControlsTable->clearRows();
-    
-    // todo: subsections need sorting?
-    std::string label, control_name;
+    pControlsTable->clearColumns();
+
+    std::string filename;
+    switch ((LLKeyConflictHandler::ESourceMode)mEditingMode)
+    {
+    case LLKeyConflictHandler::MODE_THIRD_PERSON:
+    case LLKeyConflictHandler::MODE_FIRST_PERSON:
+    case LLKeyConflictHandler::MODE_EDIT:
+    case LLKeyConflictHandler::MODE_EDIT_AVATAR:
+    case LLKeyConflictHandler::MODE_SITTING:
+        filename = "control_table_contents.xml";
+        break;
+    default:
+        // 'saved settings' mode doesn't have UI or actual settings yet
+        LL_INFOS() << "Unimplemented mode" << LL_ENDL;
+        return;
+    }
+
+    std::string full_filename = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, filename);
+    LLSimpleXUIParser parser;
+    LLScrollListCtrl::Contents contents;
+    if (!parser.readXUI(full_filename, contents)
+        || !contents.validateBlock())
+    {
+        LL_INFOS() << "Failed to load" << LL_ENDL;
+        return;
+    }
+
+    for (LLInitParam::ParamIterator<LLScrollListColumn::Params>::const_iterator row_it = contents.columns.begin();
+        row_it != contents.columns.end();
+        ++row_it)
+    {
+        pControlsTable->addColumn(*row_it);
+    }
+
     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;
+    cell_params.value = "";
 
-    controls_to_icon_t::const_iterator iter = commands_and_headers.begin();
-    controls_to_icon_t::const_iterator end = commands_and_headers.end();
-    for (; iter != end; ++iter)
+
+    for (LLInitParam::ParamIterator<LLScrollListItem::Params>::const_iterator row_it = contents.rows.begin();
+        row_it != contents.rows.end();
+        ++row_it)
     {
-        if (iter->second.empty())
+        std::string control = row_it->value.getValue().asString();
+        if (!control.empty() && control != "menu_separator")
         {
-            // general control
-            LLScrollListItem::Params item_params;
-            item_params.value = LLSD(iter->first);
-
-            cell_params.column = "lst_action";
-            bool enabled = mConflictHandler[mEditingMode].canAssignControl(iter->first);
-            if (hasString(iter->first))
-            {
-                label = getString(iter->first);
-            }
-            else
-            {
-                label = iter->first;
-            }
-            cell_params.value = label;
-            item_params.columns.add(cell_params);
+            // At the moment 4 collumns are hardcoded
+            LLScrollListItem::Params item_params(*row_it);
+            bool enabled = mConflictHandler[mEditingMode].canAssignControl(control);
+            item_params.enabled.setValue(enabled);
             cell_params.column = "lst_ctrl1";
-            cell_params.value = mConflictHandler[mEditingMode].getControlString(iter->first, 0);
-            cell_params.enabled = enabled;
+            cell_params.value = mConflictHandler[mEditingMode].getControlString(control, 0);
             item_params.columns.add(cell_params);
             cell_params.column = "lst_ctrl2";
-            cell_params.value = mConflictHandler[mEditingMode].getControlString(iter->first, 1);
-            cell_params.enabled = enabled;
+            cell_params.value = mConflictHandler[mEditingMode].getControlString(control, 1);
             item_params.columns.add(cell_params);
             cell_params.column = "lst_ctrl3";
-            cell_params.value = mConflictHandler[mEditingMode].getControlString(iter->first, 2);
-            cell_params.enabled = enabled;
+            cell_params.value = mConflictHandler[mEditingMode].getControlString(control, 2);
             item_params.columns.add(cell_params);
-
             pControlsTable->addRow(item_params, EAddPosition::ADD_BOTTOM);
         }
         else
         {
-            // header
-            addSeparator();
-            addGroupRow(iter->first, iter->second);
+            pControlsTable->addRow(*row_it, EAddPosition::ADD_BOTTOM);
         }
     }
 }
@@ -3262,7 +3121,6 @@ void LLPanelPreferenceControls::addSeparator()
 
 void LLPanelPreferenceControls::updateTable()
 {
-    pControlsTable->deselectAllItems();
     mEditingControl.clear();
     std::vector<LLScrollListItem*> list = pControlsTable->getAllData();
     for (S32 i = 0; i < list.size(); ++i)
@@ -3278,6 +3136,7 @@ void LLPanelPreferenceControls::updateTable()
             cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 2));
         }
     }
+    pControlsTable->deselectAllItems();
 }
 
 void LLPanelPreferenceControls::apply()
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 9100a91356..c1f58d290b 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -130,13 +130,6 @@ protected:
 	// callback for when client turns on impostors
 	void onAvatarImpostorsEnable();
 
-	// callback for commit in the "Single click on land" and "Double click on land" comboboxes.
-	void onClickActionChange();
-	// updates click/double-click action settings depending on controls values
-	void updateClickActionSettings();
-	// updates click/double-click action controls depending on values from settings.xml
-	void updateClickActionControls();
-
 public:
 	// This function squirrels away the current values of the controls so that
 	// cancel() can restore them.	
@@ -149,7 +142,6 @@ public:
 	void onClickResetCache();
 	void onClickSkin(LLUICtrl* ctrl,const LLSD& userdata);
 	void onSelectSkin();
-	void onClickSetKey();
 	void onClickSetMiddleMouse();
 	void onClickSetSounds();
 	void onClickEnablePopup();
@@ -204,7 +196,6 @@ private:
 
 	static std::string sSkin;
 	notifications_map mNotificationOptions;
-	bool mClickActionDirty; ///< Set to true when the click/double-click options get changed by user.
 	bool mGotPersonalInfo;
 	bool mOriginalIMViaEmail;
 	bool mLanguageChanged;
@@ -316,7 +307,6 @@ public:
 	void onCancelKeyBind();
 
 private:
-	void addGroupRow(const std::string &control_name, const std::string &icon);
 	void regenerateControls();
 	void populateControlTable();
 	void addSeparator();
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index c74eea6e47..01230ea26a 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -166,7 +166,8 @@ bool LLKeyConflictHandler::canAssignControl(const std::string &control_name)
     {
         return iter->second.mAssignable;
     }
-    return false;
+    // If we don't know this control means it wasn't assigned by user yet and thus is editable
+    return true;
 }
 
 bool LLKeyConflictHandler::registerControl(const std::string &control_name, U32 index, EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask)
@@ -346,7 +347,7 @@ void LLKeyConflictHandler::loadFromSettings(ESourceMode load_mode)
     // E.X. In case we need placeholder keys for conflict resolution.
     generatePlaceholders(load_mode);
 
-    if (load_mode == MODE_GENERAL)
+    if (load_mode == MODE_SAVED_SETTINGS)
     {
         // load settings clss knows about, but it also possible to load settings by name separately
         const S32 size = std::extent<decltype(saved_settings_key_controls)>::value;
@@ -383,7 +384,7 @@ void LLKeyConflictHandler::saveToSettings()
         return;
     }
 
-    if (mLoadMode == MODE_GENERAL)
+    if (mLoadMode == MODE_SAVED_SETTINGS)
     {
         control_map_t::iterator iter = mControlsMap.begin();
         control_map_t::iterator end = mControlsMap.end();
@@ -548,7 +549,7 @@ LLKeyData LLKeyConflictHandler::getDefaultControl(const std::string &control_nam
     {
         return LLKeyData();
     }
-    if (mLoadMode == MODE_GENERAL)
+    if (mLoadMode == MODE_SAVED_SETTINGS)
     {
         LLControlVariablePtr var = gSavedSettings.getControl(control_name);
         if (var)
@@ -590,7 +591,7 @@ void LLKeyConflictHandler::resetToDefaultAndResolve(const std::string &control_n
     {
         return;
     }
-    if (mLoadMode == MODE_GENERAL)
+    if (mLoadMode == MODE_SAVED_SETTINGS)
     {
         LLControlVariablePtr var = gSavedSettings.getControl(control_name);
         if (var)
@@ -639,7 +640,7 @@ void LLKeyConflictHandler::resetToDefault(const std::string &control_name)
 
 void LLKeyConflictHandler::resetToDefaults(ESourceMode mode)
 {
-    if (mode == MODE_GENERAL)
+    if (mode == MODE_SAVED_SETTINGS)
     {
         control_map_t::iterator iter = mControlsMap.begin();
         control_map_t::iterator end = mControlsMap.end();
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index a0886bedce..e339264aaa 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -62,7 +62,7 @@ public:
         MODE_EDIT,
         MODE_EDIT_AVATAR,
         MODE_SITTING,
-        MODE_GENERAL, // for settings from saved settings
+        MODE_SAVED_SETTINGS, // for settings from saved settings
         MODE_COUNT
     };
 
diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h
index 60159594c9..ac6751aac0 100644
--- a/indra/newview/lltoolpie.h
+++ b/indra/newview/lltoolpie.h
@@ -110,7 +110,6 @@ private:
 	LLPointer<LLHUDEffectBlob>	mAutoPilotDestination;
 	LLPointer<LLHUDEffectBlob>	mMouseSteerGrabPoint;
 	bool				mClockwise;			
-	bool				mBlockClickToWalk;
 	LLUUID				mMediaMouseCaptureID;
 	LLPickInfo			mPick;
 	LLPickInfo			mHoverPick;
diff --git a/indra/newview/skins/default/xui/en/control_table_contents.xml b/indra/newview/skins/default/xui/en/control_table_contents.xml
new file mode 100644
index 0000000000..00c2d27124
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/control_table_contents.xml
@@ -0,0 +1,569 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<contents>
+    <columns
+     relative_width="0.34"
+     label="Action"
+     name="lst_action" />
+    <columns
+     relative_width="0.22"
+     label="Prymary Control"
+     name="lst_ctrl1" />
+    <columns
+     relative_width="0.22"
+     label="Alternate 1"
+     name="lst_ctrl2" />
+    <columns
+     relative_width="0.22"
+     label="Alternate 2"
+     name="lst_ctrl3" />
+    <rows
+     enabled="false"
+     value="">
+        <columns
+         cell_type="icontext"
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         label="Move Actions"
+         name="lst_action"
+         value="Move_Walk_Off" />
+    </rows>
+    <rows
+     value="walk_to">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Walk to location mouse cursor points to"
+         value="Walk to" />
+    </rows>
+    <rows
+     value="teleport_to">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Teleport to location mouse cursor points to, but not all locations allow direct teleportation so you might be teleported closer to destination instead"
+         value="Teleport to" />
+    </rows>
+    <rows
+     value="push_forward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Move Forward" />
+    </rows>
+    <rows
+     value="push_backward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Move Backward" />
+    </rows>
+    <rows
+     value="turn_left">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Left" />
+    </rows>
+    <rows
+     value="turn_right">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Right" />
+    </rows>
+    <rows
+     value="slide_left">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Strafe left" />
+    </rows>
+    <rows
+     value="slide_right">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Strafe right" />
+    </rows>
+    <rows
+     value="jump">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Jump/Up" />
+    </rows>
+    <rows
+     value="push_down">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Down" />
+    </rows>
+    <rows
+     value="run_forward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Run Forward" />
+    </rows>
+    <rows
+     value="run_backward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Run Backward" />
+    </rows>
+    <rows
+     value="run_left">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Run Left" />
+    </rows>
+    <rows
+     value="run_right">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Run Right" />
+    </rows>
+    <rows
+     value="toggle_run">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Toggle Run" />
+    </rows>
+    <rows
+     value="toggle_fly">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Fly/Stop flying" />
+    </rows>
+    <rows
+     value="toggle_sit">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Sit/Stand" />
+    </rows>
+    <rows
+     value="stop_moving">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Stop Moving" />
+    </rows>
+    <rows
+     enabled="false">
+        <columns
+         cell_type="icon"
+         color="0 0 0 0.7"
+         halign="center"
+         value="menu_separator" />
+    </rows>
+    <rows
+     enabled="false"
+     value="">
+        <columns
+         cell_type="icontext"
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         label="Camera"
+         name="lst_action"
+         value="Cam_FreeCam_Off" />
+    </rows>
+    <rows
+     value="look_up">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Look Up" />
+    </rows>
+    <rows
+     value="look_down">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Look Down" />
+    </rows>
+    <rows
+     value="move_forward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Forward" />
+    </rows>
+    <rows
+     value="move_backward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Backward" />
+    </rows>
+    <rows
+     value="move_forward_fast">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Forward Fast" />
+    </rows>
+    <rows
+     value="move_backward_fast">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Backward Fast" />
+    </rows>
+    <rows
+     value="move_forward_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Forward Sitting" />
+    </rows>
+    <rows
+     value="move_backward_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Backward Sitting" />
+    </rows>
+    <rows
+     value="spin_over">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Spin Over" />
+    </rows>
+    <rows
+     value="spin_under">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Spin Under" />
+    </rows>
+    <rows
+     value="spin_over_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Spin Over" />
+    </rows>
+    <rows
+     value="spin_under_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Spin Under" />
+    </rows>
+    <rows
+     value="pan_up">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan Up" />
+    </rows>
+    <rows
+     value="pan_down">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan Down" />
+    </rows>
+    <rows
+     value="pan_left">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan Left" />
+    </rows>
+    <rows
+     value="pan_right">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan Right" />
+    </rows>
+    <rows
+     value="pan_in">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan In" />
+    </rows>
+    <rows
+     value="pan_out">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan Out" />
+    </rows>
+    <rows
+     value="spin_around_ccw">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around counterclockwise"
+         value="Counterclockwise" />
+    </rows>
+    <rows
+     value="spin_around_cw">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around clockwise"
+         value="Clockwise" />
+    </rows>
+    <rows
+     value="spin_around_ccw_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around counterclockwise sitting"
+         value="Counterclockwise Sitting" />
+    </rows>
+    <rows
+     value="spin_around_cw_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around clockwise sitting"
+         value="Clockwise Sitting" />
+    </rows>
+    <rows
+     enabled="false">
+        <columns
+         cell_type="icon"
+         color="0 0 0 0.7"
+         halign="center"
+         value="menu_separator" />
+    </rows>
+    <rows
+     enabled="false"
+     value="">
+        <columns
+         cell_type="icontext"
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         label="Editing"
+         name="lst_action"
+         value="Tool_Dozer" />
+    </rows>
+    <rows
+     value="edit_avatar_spin_ccw">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around avatar counterclockwise"
+         value="Counterclockwise" />
+    </rows>
+    <rows
+     value="edit_avatar_spin_cw">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around avatar clockwise"
+         value="Clockwise" />
+    </rows>
+    <rows
+     value="edit_avatar_spin_over">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin over avatar"
+         value="Camera Spin Over" />
+    </rows>
+    <rows
+     value="edit_avatar_spin_under">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin under avatar"
+         value="Camera Spin Under" />
+    </rows>
+    <rows
+     value="edit_avatar_move_forward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Forward" />
+    </rows>
+    <rows
+     value="edit_avatar_move_backward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Backward" />
+    </rows>
+    <rows
+     enabled="false">
+        <columns
+         cell_type="icon"
+         color="0 0 0 0.7"
+         halign="center"
+         value="menu_separator" />
+    </rows>
+    <rows
+     enabled="false"
+     value="">
+        <columns
+         cell_type="icontext"
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         label="Sound and Media"
+         name="lst_action"
+         value="Audio_Press" />
+    </rows>
+    <rows
+     value="toggle_pause_media">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Play/Pause Media" />
+    </rows>
+    <rows
+     value="toggle_enable_media">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Play/Stop All Media" />
+    </rows>
+    <rows
+     value="voice_follow_key">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Voice" />
+    </rows>
+    <rows
+     value="toggle_voice">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Toggle Voice" />
+    </rows>
+    <rows
+     value="start_chat">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Start Chat" />
+    </rows>
+    <rows
+     value="start_gesture">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Start Gesture" />
+    </rows>
+</contents>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
index b7b5280825..eca3c550d5 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
@@ -9,244 +9,6 @@
  name="controls"
  top="1"
  width="517">
-  <panel.string
-   name="walk_to">
-    Walk to
-  </panel.string>
-  <panel.string
-   name="control_view_actions">
-    View Actions
-  </panel.string>
-  <panel.string
-   name="control_about">
-    About/Profile
-  </panel.string>
-  <panel.string
-   name="control_orbit">
-    Orbit
-  </panel.string>
-  <panel.string
-   name="control_pan">
-    Pan
-  </panel.string>
-  <panel.string
-   name="control_world_map">
-    World Map
-  </panel.string>
-  <panel.string
-   name="control_zoom">
-    Zoom
-  </panel.string>
-  <panel.string
-   name="control_interactions">
-    Interactions
-  </panel.string>
-  <panel.string
-   name="control_build">
-    Build
-  </panel.string>
-  <panel.string
-   name="control_drag">
-    Drag
-  </panel.string>
-  <panel.string
-   name="control_edit">
-    Edit
-  </panel.string>
-  <panel.string
-   name="control_menu">
-    Menu
-  </panel.string>
-  <panel.string
-   name="control_open">
-    Open
-  </panel.string>
-  <panel.string
-   name="control_touch">
-    Touch
-  </panel.string>
-  <panel.string
-   name="control_wear">
-    Wear
-  </panel.string>
-  <panel.string
-   name="control_movements">
-    Move Actions
-  </panel.string>
-  <panel.string
-   name="teleport_to">
-    Teleport to
-  </panel.string>
-  <panel.string
-   name="toggle_sit">
-    Sit/Stand
-  </panel.string>
-  <panel.string
-   name="control_teleportto">
-    Teleport To
-  </panel.string>
-  <panel.string
-   name="push_forward">
-    Move Forward
-  </panel.string>
-  <panel.string
-   name="push_backward">
-    Move Backward
-  </panel.string>
-  <panel.string
-   name="turn_left">
-    Left
-  </panel.string>
-  <panel.string
-   name="turn_right">
-    Right
-  </panel.string>
-  <!--(check with move floater)-->
-  <panel.string
-   name="slide_left">
-    Strafe left
-  </panel.string>
-  <panel.string
-   name="slide_right">
-    Strafe right
-  </panel.string>
-  <panel.string
-   name="jump">
-    Jump/Up
-  </panel.string>
-  <panel.string
-   name="push_down">
-    Down
-  </panel.string>
-  <panel.string
-   name="control_run">
-    Run
-  </panel.string>
-  <panel.string
-   name="run_forward">
-    Run Forward
-  </panel.string>
-  <panel.string
-   name="run_backward">
-    Run Backward
-  </panel.string>
-  <panel.string
-   name="run_left">
-    Run Left
-  </panel.string>
-  <panel.string
-   name="run_right">
-    Run Right
-  </panel.string>
-  <panel.string
-   name="toggle_run">
-    Toggle Run
-  </panel.string>
-  <panel.string
-   name="toggle_fly">
-    Fly/Stop flying
-  </panel.string>
-  <panel.string
-   name="stop_moving">
-    Stop Moving
-  </panel.string>
-  <panel.string
-   name="control_camera">
-    Camera
-  </panel.string>
-  <panel.string
-   name="look_up">
-    Look Up
-  </panel.string>
-  <panel.string
-   name="look_down">
-    Look Down
-  </panel.string>
-  <panel.string
-   name="move_forward">
-    Camera Forward
-  </panel.string>
-  <panel.string
-   name="move_backward">
-    Camera Backward
-  </panel.string>
-  <panel.string
-   name="move_forward_fast">
-    Camera Forward Fast
-  </panel.string>
-  <panel.string
-   name="move_backward_fast">
-    Camera Backward Fast
-  </panel.string>
-  <panel.string
-   name="move_forward_sitting">
-    Camera Forward Sitting
-  </panel.string>
-  <panel.string
-   name="move_backward_sitting">
-    Camera Backward Sitting
-  </panel.string>
-  <panel.string
-   name="spin_over">
-    Camera Spin Over
-  </panel.string>
-  <panel.string
-   name="spin_under">
-    Camera Spin Under
-  </panel.string>
-  <panel.string
-   name="spin_over_sitting">
-    Camera Spin Over
-  </panel.string>
-  <panel.string
-   name="spin_under_sitting">
-    Camera Spin Under
-  </panel.string>
-  <panel.string
-   name="pan_up">
-    Camera Pan Up
-  </panel.string>
-  <panel.string
-   name="pan_down">
-    Camera Pan Down
-  </panel.string>
-  <panel.string
-   name="pan_left">
-    Camera Pan Left
-  </panel.string>
-  <panel.string
-   name="pan_right">
-    Camera Pan Right
-  </panel.string>
-  <panel.string
-   name="pan_left">
-    Camera Pan In
-  </panel.string>
-  <panel.string
-   name="pan_right">
-    Camera Pan Out
-  </panel.string>
-  <panel.string
-   name="control_mediacontent">
-    Sound and Media
-  </panel.string>
-  <panel.string
-   name="toggle_pause_media">
-    Play/Pause Media
-  </panel.string>
-  <panel.string
-   name="toggle_enable_media">
-    Play/Stop All Media
-  </panel.string>
-  <panel.string
-   name="voice_follow_key">
-    Voice
-  </panel.string>
-  <panel.string
-   name="toggle_voice">
-    Toggle Voice
-  </panel.string>
-
   <combo_box
    follows="top|left"
    layout="topleft"
@@ -299,22 +61,6 @@
    right="-3"
    can_sort="false"
    multi_select="false"
-   name="controls_list">
-    <scroll_list.columns
-     relative_width="0.34"
-     label="Action"
-     name="lst_action" />
-    <scroll_list.columns
-     relative_width="0.22"
-     label="Control Method 1"
-     name="lst_ctrl1" />
-    <scroll_list.columns
-     relative_width="0.22"
-     label="Control Method 2"
-     name="lst_ctrl2" />
-    <scroll_list.columns
-     relative_width="0.22"
-     label="Control Method 3"
-     name="lst_ctrl3" />
-  </scroll_list>
+   name="controls_list"
+   fg_disable_color="ScrollUnselectedColor"/>
 </panel>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_move.xml b/indra/newview/skins/default/xui/en/panel_preferences_move.xml
index 8794e3bf95..d106456b31 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_move.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_move.xml
@@ -195,70 +195,6 @@
    name="invert_mouse"
    top_delta="0"
    width="128" />
-  <text
-   follows="left|top"
-   type="string"
-   length="1"
-   height="10"
-   layout="topleft"
-   left="86"
-   name="single_click_action_lbl"
-   width="150"
-   top_pad="20">
-    Single click on land:
-  </text>
-  <combo_box
-   height="23"
-   layout="topleft"
-   left_pad="10"
-   top_delta="-6"
-   name="single_click_action_combo"
-   width="200">
-    <combo_box.item
-     label="No action"
-     name="0"
-     value="0"/>
-    <combo_box.item
-     label="Move to clicked point"
-     name="1"
-     value="1"/>
-    <combo_box.commit_callback
-     function="Pref.ClickActionChange"/>
-  </combo_box>
-  <text
-   follows="left|top"
-   type="string"
-   length="1"
-   height="10"
-   layout="topleft"
-   left="86"
-   name="double_click_action_lbl"
-   width="150"
-   top_pad="12">
-    Double click on land:
-  </text>
-  <combo_box
-   height="23"
-   layout="topleft"
-   left_pad="10"
-   top_delta="-6"
-   name="double_click_action_combo"
-   width="200">
-    <combo_box.item
-     label="No action"
-     name="0"
-     value="0"/>
-    <combo_box.item
-     label="Move to clicked point"
-     name="1"
-     value="1"/>
-    <combo_box.item
-     label="Teleport to clicked point"
-     name="2"
-     value="2"/>
-    <combo_box.commit_callback
-     function="Pref.ClickActionChange"/>
-  </combo_box>
   <button
    height="23"
    label="Other Devices"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
index 90f2ca2713..6b54438b05 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
@@ -463,37 +463,13 @@
   enabled_control="EnableVoiceChat"
   control_name="PushToTalkToggle"
   height="15"
-  label="Toggle speak on/off when I press:"
+  label="Toggle speak on/off when I press button in toolbar"
   layout="topleft"
   left="44"
   name="push_to_talk_toggle_check"
   width="237"
   tool_tip="When in toggle mode, press and release the trigger key ONCE to switch your microphone on or off. When not in toggle mode, the microphone broadcasts your voice only while the trigger is being held down."
   top_pad="3"/>
-  <line_editor
-   follows="top|left"
-   control_name="PushToTalkButton"
-   enabled="false"
-   enabled_control="EnableVoiceChat"
-   height="23"
-   left="80"
-   max_length_bytes="200"
-   name="modifier_combo"
-   label="Push-to-Speak trigger"
-   top_pad="3"
-   width="200" />
-  <button
-   layout="topleft"
-   follows="top|left"
-   enabled_control="EnableVoiceChat"
-   height="23"
-   label="Set Key"
-   left_pad="5"
-   name="set_voice_hotkey_button"
-   width="100">
-    <button.commit_callback
-    function="Pref.VoiceSetKey" />
-  </button>
   <button
      enabled_control="EnableVoiceChat"
      follows="top|left"
-- 
cgit v1.2.3


From b8c5ae8d8fcf9219112c4ab48233615732737e44 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Thu, 3 Oct 2019 19:46:12 +0300
Subject: SL-6109 Better menu accelerator support and slight reorganization

---
 indra/llui/llmenugl.cpp                  |  21 +++
 indra/llui/llmenugl.h                    |   2 +
 indra/newview/CMakeLists.txt             |   2 +
 indra/newview/llfloaterpreference.cpp    | 306 +------------------------------
 indra/newview/llfloaterpreference.h      |   5 +-
 indra/newview/llkeyconflict.cpp          |  21 +++
 indra/newview/llkeyconflict.h            |   2 +
 indra/newview/llpanelpresetspulldown.cpp |   1 -
 indra/newview/llsetkeybinddialog.cpp     | 298 ++++++++++++++++++++++++++++++
 indra/newview/llsetkeybinddialog.h       |  88 +++++++++
 indra/newview/llstartup.cpp              |   1 -
 11 files changed, 440 insertions(+), 307 deletions(-)
 create mode 100644 indra/newview/llsetkeybinddialog.cpp
 create mode 100644 indra/newview/llsetkeybinddialog.h

diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index e6a3de281e..986f3362b7 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -3514,6 +3514,27 @@ S32 LLMenuBarGL::getRightmostMenuEdge()
 	return (*item_iter)->getRect().mRight;
 }
 
+bool LLMenuBarGL::hasAccelerator(const KEY &key, const MASK &mask) const
+{
+    if (key == KEY_NONE)
+    {
+        return false;
+    }
+
+    LLMenuKeyboardBinding *accelerator = NULL;
+    std::list<LLMenuKeyboardBinding*>::const_iterator list_it;
+    for (list_it = mAccelerators.begin(); list_it != mAccelerators.end(); ++list_it)
+    {
+        accelerator = *list_it;
+        if ((accelerator->mKey == key) && (accelerator->mMask == (mask & MASK_NORMALKEYS)))
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 // add a vertical separator to this menu
 BOOL LLMenuBarGL::addSeparator()
 {
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 3a6b849e73..0653864892 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -792,6 +792,8 @@ public:
 
 	void resetMenuTrigger() { mAltKeyTrigger = FALSE; }
 
+	bool hasAccelerator(const KEY &key, const MASK &mask) const;
+
 private:
 	// add a menu - this will create a drop down menu.
 	virtual BOOL appendMenu( LLMenuGL* menu );
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index a35d0cba50..8345d5c445 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -551,6 +551,7 @@ set(viewer_SOURCE_FILES
     llsecapi.cpp
     llsechandler_basic.cpp
     llselectmgr.cpp
+    llsetkeybinddialog.cpp
     llshareavatarhandler.cpp
     llsidepanelappearance.cpp
     llsidepanelinventory.cpp
@@ -1172,6 +1173,7 @@ set(viewer_HEADER_FILES
     llsecapi.h
     llsechandler_basic.h
     llselectmgr.h
+    llsetkeybinddialog.h
     llsidepanelappearance.h
     llsidepanelinventory.h
     llsidepanelinventorysubpanel.h
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 2354be25e9..6ee1bbee1a 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -43,7 +43,6 @@
 #include "llcombobox.h"
 #include "llcommandhandler.h"
 #include "lldirpicker.h"
-#include "lldrawfrustum.h"
 #include "lleventtimer.h"
 #include "llfeaturemanager.h"
 #include "llfocusmgr.h"
@@ -161,306 +160,6 @@ struct LabelTable : public LLInitParam::Block<LabelTable>
     {}
 };
 
-// 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 CAN_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 | CAN_IGNORE_MASKS;
-
-class LLSetKeyBindDialog : public LLModalDialog, public LLDrawFrustum
-{
-public:
-	LLSetKeyBindDialog(const LLSD& key);
-	~LLSetKeyBindDialog();
-
-	/*virtual*/ BOOL postBuild();
-    /*virtual*/ void onClose(bool app_quiting);
-    /*virtual*/ void draw();
-
-	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);
-	static void onClickTimeout(void* user_data, MASK mask);
-
-	class Updater;
-
-private:
-	void setKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore);
-	LLPanelPreferenceControls* pParent;
-	LLCheckBoxCtrl* pCheckBox;
-
-	U32 mKeyFilterMask;
-	Updater *pUpdater;
-};
-
-class LLSetKeyBindDialog::Updater : public LLEventTimer
-{
-public:
-
-    typedef boost::function<void(MASK)> callback_t;
-
-    Updater(callback_t cb, F32 period, MASK mask)
-        :LLEventTimer(period),
-        mMask(mask),
-        mCallback(cb)
-    {
-        mEventTimer.start();
-    }
-
-    virtual ~Updater(){}
-
-protected:
-    BOOL tick()
-    {
-        mCallback(mMask);
-        // Deletes itseft after execution
-        return TRUE;
-    }
-
-private:
-    MASK mMask;
-    callback_t mCallback;
-};
-
-LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key)
-  : LLModalDialog(key),
-	pParent(NULL),
-	mKeyFilterMask(DEFAULT_KEY_FILTER),
-	pUpdater(NULL)
-{
-}
-
-LLSetKeyBindDialog::~LLSetKeyBindDialog()
-{
-}
-
-//virtual
-BOOL LLSetKeyBindDialog::postBuild()
-{
-	childSetAction("SetEmpty", onBlank, this);
-	childSetAction("Default", onDefault, this);
-	childSetAction("Cancel", onCancel, this);
-	getChild<LLUICtrl>("Cancel")->setFocus(TRUE);
-
-	pCheckBox = getChild<LLCheckBoxCtrl>("ignore_masks");
-
-	gFocusMgr.setKeystrokesOnly(TRUE);
-	
-	return TRUE;
-}
-
-//virtual
-void LLSetKeyBindDialog::onClose(bool app_quiting)
-{
-    if (pParent)
-    {
-        pParent->onCancelKeyBind();
-        pParent = NULL;
-    }
-    if (pUpdater)
-    {
-        // Doubleclick timer has't fired, delete it
-        delete pUpdater;
-        pUpdater = NULL;
-    }
-    LLModalDialog::onClose(app_quiting);
-}
-
-//virtual
-void LLSetKeyBindDialog::draw()
-{
-    LLRect local_rect;
-    drawFrustum(local_rect, this, (LLView*)getDragHandle(), hasFocus());
-    LLModalDialog::draw();
-}
-
-void LLSetKeyBindDialog::setParent(LLPanelPreferenceControls* parent, U32 key_mask)
-{
-    pParent = parent;
-    setFrustumOrigin(parent);
-    mKeyFilterMask = key_mask;
-
-    LLTextBase *text_ctrl = getChild<LLTextBase>("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);
-
-    bool can_ignore_masks = (key_mask & CAN_IGNORE_MASKS) != 0;
-    pCheckBox->setVisible(can_ignore_masks);
-    pCheckBox->setValue(false);
-}
-
-BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
-{
-    if ((key == 'Q' && mask == MASK_CONTROL)
-        || key == KEY_ESCAPE)
-    {
-        closeFloater();
-        return TRUE;
-    }
-
-    if (key == KEY_DELETE)
-    {
-        setKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
-        closeFloater();
-        return FALSE;
-    }
-
-    // forbidden keys
-    if (key == KEY_NONE
-        || key == KEY_RETURN
-        || key == KEY_BACKSPACE)
-    {
-        return FALSE;
-    }
-
-    if ((mKeyFilterMask & ALLOW_MASKS) == 0
-        && (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT))
-    {
-        // mask by themself are not allowed
-        return FALSE;
-    }
-    else if ((mKeyFilterMask & ALLOW_KEYS) == 0)
-    {
-        // basic keys not allowed
-        return FALSE;
-    }
-    else if ((mKeyFilterMask & ALLOW_MASK_KEYS) == 0 && mask != 0)
-    {
-        // masked keys not allowed
-        return FALSE;
-    }
-
-    setKeyBind(CLICK_NONE, key, mask, pCheckBox->getValue().asBoolean());
-    closeFloater();
-    return TRUE;
-}
-
-BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down)
-{
-    BOOL result = FALSE;
-    if (!pParent)
-    {
-        // we already processed 'down' event, this is 'up', consume
-        closeFloater();
-        result = TRUE;
-    }
-    if (!result && clicktype == CLICK_LEFT)
-    {
-        // try handling buttons first
-        if (down)
-        {
-            result = LLView::handleMouseDown(x, y, mask);
-        }
-        else
-        {
-            result = LLView::handleMouseUp(x, y, mask);
-        }
-        if (result)
-        {
-            setFocus(TRUE);
-            gFocusMgr.setKeystrokesOnly(TRUE);
-        }
-        // ignore selection related combinations
-        else if (down && (mask & (MASK_SHIFT | MASK_CONTROL)) == 0)
-        {
-            // this can be a double click, wait a bit;
-            if (!pUpdater)
-            {
-                // Note: default doubleclick time is 500ms, but can stretch up to 5s
-                pUpdater = new Updater(boost::bind(&onClickTimeout, this, _1), 0.7f, mask);
-                result = TRUE;
-            }
-        }
-    }
-
-    if (!result
-        && (clicktype != CLICK_LEFT) // subcases were handled above
-        && ((mKeyFilterMask & ALLOW_MOUSE) != 0)
-        && (clicktype != CLICK_RIGHT || mask != 0) // reassigning menu button is not supported
-        && ((mKeyFilterMask & ALLOW_MASK_MOUSE) != 0 || mask == 0)) // reserved for selection
-    {
-        setKeyBind(clicktype, KEY_NONE, mask, pCheckBox->getValue().asBoolean());
-        result = TRUE;
-        if (!down)
-        {
-            // wait for 'up' event before closing
-            // alternative: set pUpdater
-            closeFloater();
-        }
-    }
-
-    return result;
-}
-
-//static
-void LLSetKeyBindDialog::onCancel(void* user_data)
-{
-    LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
-    self->closeFloater();
-}
-
-//static
-void LLSetKeyBindDialog::onBlank(void* user_data)
-{
-    LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
-    // tmp needs 'no key' button
-    self->setKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
-    self->closeFloater();
-}
-
-//static
-void LLSetKeyBindDialog::onDefault(void* user_data)
-{
-    LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
-    if (self->pParent)
-    {
-        self->pParent->onDefaultKeyBind();
-        self->pParent = NULL;
-    }
-    self->closeFloater();
-}
-
-//static
-void LLSetKeyBindDialog::onClickTimeout(void* user_data, MASK mask)
-{
-    LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
-
-    // timer will delete itself after timeout
-    self->pUpdater = NULL;
-
-    self->setKeyBind(CLICK_LEFT, KEY_NONE, mask, self->pCheckBox->getValue().asBoolean());
-    self->closeFloater();
-}
-
-void LLSetKeyBindDialog::setKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore)
-{
-    if (pParent)
-    {
-        pParent->onSetKeyBind(click, key, mask, ignore);
-        pParent = NULL;
-    }
-}
-
 
 // global functions 
 
@@ -3248,11 +2947,11 @@ void LLPanelPreferenceControls::onModeCommit()
 }
 
 // todo: copy onSetKeyBind to interface and inherit from interface
-void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore_mask)
+bool LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore_mask)
 {
     if (!mConflictHandler[mEditingMode].canAssignControl(mEditingControl))
     {
-        return;
+        return true;
     }
 
     if ( mEditingColumn > 0)
@@ -3261,6 +2960,7 @@ void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MAS
     }
 
     updateTable();
+    return true;
 }
 
 void LLPanelPreferenceControls::onRestoreDefaults()
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index c1f58d290b..9734ea30a2 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -37,6 +37,7 @@
 #include "llavatarpropertiesprocessor.h"
 #include "llconversationlog.h"
 #include "llsearcheditor.h"
+#include "llsetkeybinddialog.h"
 #include "llkeyconflict.h"
 
 class LLConversationLogObserver;
@@ -285,7 +286,7 @@ private:
 	LOG_CLASS(LLPanelPreferenceGraphics);
 };
 
-class LLPanelPreferenceControls : public LLPanelPreference
+class LLPanelPreferenceControls : public LLPanelPreference, public LLKeyBindResponderInterface
 {
 	LOG_CLASS(LLPanelPreferenceControls);
 public:
@@ -301,7 +302,7 @@ public:
 
 	void onListCommit();
 	void onModeCommit();
-	void onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore_mask);
+	bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore_mask);
 	void onRestoreDefaults();
 	void onDefaultKeyBind();
 	void onCancelKeyBind();
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index 01230ea26a..bad4e4a2d8 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -38,6 +38,7 @@
 #include "llkeyboard.h"
 #include "llviewercontrol.h"
 #include "llviewerinput.h"
+#include "llviewermenu.h"
 #include "llxuiparser.h"
 //#include "llstring.h"
 
@@ -170,6 +171,22 @@ bool LLKeyConflictHandler::canAssignControl(const std::string &control_name)
     return true;
 }
 
+// static
+bool LLKeyConflictHandler::isReservedByMenu(const KEY &key, const MASK &mask)
+{
+    return gMenuBarView->hasAccelerator(key, mask) || gLoginMenuBarView->hasAccelerator(key, mask);
+}
+
+// static
+bool LLKeyConflictHandler::isReservedByMenu(const LLKeyData &data)
+{
+    if (data.mMouse != CLICK_NONE)
+    {
+        return false;
+    }
+    return gMenuBarView->hasAccelerator(data.mKey, data.mMask) || gLoginMenuBarView->hasAccelerator(data.mKey, data.mMask);
+}
+
 bool LLKeyConflictHandler::registerControl(const std::string &control_name, U32 index, EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask)
 {
     if (control_name.empty())
@@ -186,6 +203,10 @@ bool LLKeyConflictHandler::registerControl(const std::string &control_name, U32
     {
         return true;
     }
+    if (isReservedByMenu(data))
+    {
+        return false;
+    }
     if (removeConflicts(data, type_data.mConflictMask))
     {
         type_data.mKeyBind.replaceKeyData(data, index);
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index e339264aaa..5c3b860ec6 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -80,6 +80,8 @@ public:
     bool canHandleMouse(const std::string &control_name, EMouseClickType mouse_ind, MASK mask);
     bool canHandleMouse(const std::string &control_name, S32 mouse_ind, MASK mask); //Just for convinience
     bool canAssignControl(const std::string &control_name);
+    static bool isReservedByMenu(const KEY &key, const MASK &mask);
+    static bool isReservedByMenu(const LLKeyData &data);
     bool registerControl(const std::string &control_name, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask, bool ignore_mask); //todo: return conflicts?
 
     LLKeyData getControl(const std::string &control_name, U32 data_index);
diff --git a/indra/newview/llpanelpresetspulldown.cpp b/indra/newview/llpanelpresetspulldown.cpp
index 9b4dc5474a..1a49cbc250 100644
--- a/indra/newview/llpanelpresetspulldown.cpp
+++ b/indra/newview/llpanelpresetspulldown.cpp
@@ -34,7 +34,6 @@
 #include "llbutton.h"
 #include "lltabcontainer.h"
 #include "llfloaterreg.h"
-#include "llfloaterpreference.h"
 #include "llpresetsmanager.h"
 #include "llsliderctrl.h"
 #include "llscrolllistctrl.h"
diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp
new file mode 100644
index 0000000000..0ad71cb372
--- /dev/null
+++ b/indra/newview/llsetkeybinddialog.cpp
@@ -0,0 +1,298 @@
+/** 
+ * @file llsetkeybinddialog.cpp
+ * @brief LLSetKeyBindDialog class implementation.
+ *
+ * $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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llsetkeybinddialog.h"
+
+//#include "llkeyboard.h"
+
+#include "llbutton.h"
+#include "llcheckboxctrl.h"
+#include "lleventtimer.h"
+#include "llfocusmgr.h"
+
+class LLSetKeyBindDialog::Updater : public LLEventTimer
+{
+public:
+
+    typedef boost::function<void(MASK)> callback_t;
+
+    Updater(callback_t cb, F32 period, MASK mask)
+        :LLEventTimer(period),
+        mMask(mask),
+        mCallback(cb)
+    {
+        mEventTimer.start();
+    }
+
+    virtual ~Updater(){}
+
+protected:
+    BOOL tick()
+    {
+        mCallback(mMask);
+        // Deletes itseft after execution
+        return TRUE;
+    }
+
+private:
+    MASK mMask;
+    callback_t mCallback;
+};
+
+LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key)
+    : LLModalDialog(key),
+    pParent(NULL),
+    mKeyFilterMask(DEFAULT_KEY_FILTER),
+    pUpdater(NULL)
+{
+}
+
+LLSetKeyBindDialog::~LLSetKeyBindDialog()
+{
+}
+
+//virtual
+BOOL LLSetKeyBindDialog::postBuild()
+{
+    childSetAction("SetEmpty", onBlank, this);
+    childSetAction("Default", onDefault, this);
+    childSetAction("Cancel", onCancel, this);
+    getChild<LLUICtrl>("Cancel")->setFocus(TRUE);
+
+    pCheckBox = getChild<LLCheckBoxCtrl>("ignore_masks");
+
+    gFocusMgr.setKeystrokesOnly(TRUE);
+
+    return TRUE;
+}
+
+//virtual
+void LLSetKeyBindDialog::onClose(bool app_quiting)
+{
+    if (pParent)
+    {
+        pParent->onCancelKeyBind();
+        pParent = NULL;
+    }
+    if (pUpdater)
+    {
+        // Doubleclick timer has't fired, delete it
+        delete pUpdater;
+        pUpdater = NULL;
+    }
+    LLModalDialog::onClose(app_quiting);
+}
+
+//virtual
+void LLSetKeyBindDialog::draw()
+{
+    LLRect local_rect;
+    drawFrustum(local_rect, this, (LLView*)getDragHandle(), hasFocus());
+    LLModalDialog::draw();
+}
+
+void LLSetKeyBindDialog::setParent(LLPanelPreferenceControls* parent, U32 key_mask)
+{
+    pParent = parent;
+    setFrustumOrigin(parent);
+    mKeyFilterMask = key_mask;
+
+    LLTextBase *text_ctrl = getChild<LLTextBase>("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);
+
+    bool can_ignore_masks = (key_mask & CAN_IGNORE_MASKS) != 0;
+    pCheckBox->setVisible(can_ignore_masks);
+    pCheckBox->setValue(false);
+}
+
+BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
+{
+    if ((key == 'Q' && mask == MASK_CONTROL)
+        || key == KEY_ESCAPE)
+    {
+        closeFloater();
+        return TRUE;
+    }
+
+    if (key == KEY_DELETE)
+    {
+        setKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
+        closeFloater();
+        return FALSE;
+    }
+
+    // forbidden keys
+    if (key == KEY_NONE
+        || key == KEY_RETURN
+        || key == KEY_BACKSPACE)
+    {
+        return FALSE;
+    }
+
+    if ((mKeyFilterMask & ALLOW_MASKS) == 0
+        && (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT))
+    {
+        // mask by themself are not allowed
+        return FALSE;
+    }
+    else if ((mKeyFilterMask & ALLOW_KEYS) == 0)
+    {
+        // basic keys not allowed
+        return FALSE;
+    }
+    else if ((mKeyFilterMask & ALLOW_MASK_KEYS) == 0 && mask != 0)
+    {
+        // masked keys not allowed
+        return FALSE;
+    }
+
+    setKeyBind(CLICK_NONE, key, mask, pCheckBox->getValue().asBoolean());
+    closeFloater();
+    return TRUE;
+}
+
+BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down)
+{
+    BOOL result = FALSE;
+    if (!pParent)
+    {
+        // we already processed 'down' event, this is 'up', consume
+        closeFloater();
+        result = TRUE;
+    }
+    if (!result && clicktype == CLICK_LEFT)
+    {
+        // try handling buttons first
+        if (down)
+        {
+            result = LLView::handleMouseDown(x, y, mask);
+        }
+        else
+        {
+            result = LLView::handleMouseUp(x, y, mask);
+        }
+        if (result)
+        {
+            setFocus(TRUE);
+            gFocusMgr.setKeystrokesOnly(TRUE);
+        }
+        // ignore selection related combinations
+        else if (down && (mask & (MASK_SHIFT | MASK_CONTROL)) == 0)
+        {
+            // this can be a double click, wait a bit;
+            if (!pUpdater)
+            {
+                // Note: default doubleclick time is 500ms, but can stretch up to 5s
+                pUpdater = new Updater(boost::bind(&onClickTimeout, this, _1), 0.7f, mask);
+                result = TRUE;
+            }
+        }
+    }
+
+    if (!result
+        && (clicktype != CLICK_LEFT) // subcases were handled above
+        && ((mKeyFilterMask & ALLOW_MOUSE) != 0)
+        && (clicktype != CLICK_RIGHT || mask != 0) // reassigning menu button is not supported
+        && ((mKeyFilterMask & ALLOW_MASK_MOUSE) != 0 || mask == 0)) // reserved for selection
+    {
+        setKeyBind(clicktype, KEY_NONE, mask, pCheckBox->getValue().asBoolean());
+        result = TRUE;
+        if (!down)
+        {
+            // wait for 'up' event before closing
+            // alternative: set pUpdater
+            closeFloater();
+        }
+    }
+
+    return result;
+}
+
+//static
+void LLSetKeyBindDialog::onCancel(void* user_data)
+{
+    LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
+    self->closeFloater();
+}
+
+//static
+void LLSetKeyBindDialog::onBlank(void* user_data)
+{
+    LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
+    // tmp needs 'no key' button
+    self->setKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
+    self->closeFloater();
+}
+
+//static
+void LLSetKeyBindDialog::onDefault(void* user_data)
+{
+    LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
+    if (self->pParent)
+    {
+        self->pParent->onDefaultKeyBind();
+        self->pParent = NULL;
+    }
+    self->closeFloater();
+}
+
+//static
+void LLSetKeyBindDialog::onClickTimeout(void* user_data, MASK mask)
+{
+    LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
+
+    // timer will delete itself after timeout
+    self->pUpdater = NULL;
+
+    self->setKeyBind(CLICK_LEFT, KEY_NONE, mask, self->pCheckBox->getValue().asBoolean());
+    self->closeFloater();
+}
+
+void LLSetKeyBindDialog::setKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore)
+{
+    if (pParent)
+    {
+        pParent->onSetKeyBind(click, key, mask, ignore);
+        pParent = NULL;
+    }
+}
+
diff --git a/indra/newview/llsetkeybinddialog.h b/indra/newview/llsetkeybinddialog.h
new file mode 100644
index 0000000000..fb3b2a2269
--- /dev/null
+++ b/indra/newview/llsetkeybinddialog.h
@@ -0,0 +1,88 @@
+/** 
+ * @file llsetkeybinddialog.h
+ * @brief LLSetKeyBindDialog class definition
+ *
+ * $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_LLSETKEYBINDDIALOG_H
+#define LL_LLSETKEYBINDDIALOG_H
+
+#include "llmodaldialog.h"
+#include "lldrawfrustum.h"
+
+class LLCheckBoxCtrl;
+
+// 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 CAN_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 | CAN_IGNORE_MASKS;
+
+
+class LLKeyBindResponderInterface
+{
+public:
+    virtual ~LLKeyBindResponderInterface();
+
+    virtual void onCancelKeyBind();
+    virtual void onDefaultKeyBind();
+    // returns true if parent failed to set key due to key being in use
+    virtual bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore);
+};
+
+class LLSetKeyBindDialog : public LLModalDialog, public LLDrawFrustum
+{
+public:
+    LLSetKeyBindDialog(const LLSD& key);
+    ~LLSetKeyBindDialog();
+
+    /*virtual*/ BOOL postBuild();
+    /*virtual*/ void onClose(bool app_quiting);
+    /*virtual*/ void draw();
+
+    void setParent(LLKeyBindResponderInterface* 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);
+    static void onClickTimeout(void* user_data, MASK mask);
+
+    class Updater;
+
+private:
+    void setKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore);
+    LLKeyBindResponderInterface* pParent;
+    LLCheckBoxCtrl* pCheckBox;
+
+    U32 mKeyFilterMask;
+    Updater *pUpdater;
+};
+
+
+#endif  // LL_LLSETKEYBINDDIALOG_H
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 3771797929..b1bdaa1c1a 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -106,7 +106,6 @@
 //#include "llfirstuse.h"
 #include "llfloaterhud.h"
 #include "llfloaterland.h"
-#include "llfloaterpreference.h"
 #include "llfloatertopobjects.h"
 #include "llfloaterworldmap.h"
 #include "llgesturemgr.h"
-- 
cgit v1.2.3


From 6aab234105d6eed022afbea388ae21530c7e99dd Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Thu, 3 Oct 2019 22:45:29 +0300
Subject: SL-6109 Remade 'ignore' list processing, renamed and reformed
 keybindings

---
 indra/llcommon/llkeybind.cpp                       |   9 +-
 indra/llcommon/llkeybind.h                         |   3 +-
 indra/llui/llscrolllistcell.h                      |   2 +-
 indra/newview/CMakeLists.txt                       |   2 +-
 indra/newview/app_settings/key_bindings.xml        | 302 +++++++++++++++++
 indra/newview/app_settings/keys.xml                | 363 ---------------------
 indra/newview/llappviewer.cpp                      |   4 +-
 indra/newview/llfloaterpreference.cpp              |  20 +-
 indra/newview/llfloaterpreference.h                |   8 +-
 indra/newview/llkeyconflict.cpp                    |  18 +-
 indra/newview/llpanelpresetspulldown.cpp           |   1 +
 indra/newview/llsetkeybinddialog.cpp               |  18 +-
 indra/newview/llsetkeybinddialog.h                 |  18 +-
 indra/newview/llviewerinput.cpp                    | 164 ++++------
 indra/newview/llviewerinput.h                      |  28 +-
 .../default/xui/en/control_table_contents.xml      |  14 +-
 .../skins/default/xui/en/floater_select_key.xml    |  15 +-
 17 files changed, 445 insertions(+), 544 deletions(-)
 create mode 100644 indra/newview/app_settings/key_bindings.xml
 delete mode 100644 indra/newview/app_settings/keys.xml

diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp
index ff88a9c9aa..46a3230240 100644
--- a/indra/llcommon/llkeybind.cpp
+++ b/indra/llcommon/llkeybind.cpp
@@ -92,14 +92,11 @@ LLSD LLKeyData::asLLSD() const
     LLSD data;
     data["mouse"] = (LLSD::Integer)mMouse;
     data["key"] = (LLSD::Integer)mKey;
+    data["mask"] = (LLSD::Integer)mMask;
     if (mIgnoreMasks)
     {
         data["ignore_accelerators"] = (LLSD::Boolean)mIgnoreMasks;
     }
-    else
-    {
-        data["mask"] = (LLSD::Integer)mMask;
-    }
     return data;
 }
 
@@ -147,7 +144,7 @@ bool LLKeyData::canHandle(const LLKeyData& data) const
 {
     if (data.mKey == mKey
         && data.mMouse == mMouse
-        && (mIgnoreMasks || data.mMask == mMask))
+        && ((mIgnoreMasks && (data.mMask & mMask) == data.mMask) || data.mMask == mMask))
     {
         return true;
     }
@@ -158,7 +155,7 @@ bool LLKeyData::canHandle(EMouseClickType mouse, KEY key, MASK mask) const
 {
     if (mouse == mMouse
         && key == mKey
-        && (mIgnoreMasks || mask == mMask))
+        && ((mIgnoreMasks && (mask & mMask) == mask) || mask == mMask))
     {
         return true;
     }
diff --git a/indra/llcommon/llkeybind.h b/indra/llcommon/llkeybind.h
index 39cb668aac..ad0ebec67c 100644
--- a/indra/llcommon/llkeybind.h
+++ b/indra/llcommon/llkeybind.h
@@ -53,7 +53,8 @@ public:
     EMouseClickType mMouse;
     KEY mKey;
     MASK mMask;
-    bool mIgnoreMasks;
+    // Either to expect exact match or ignore not expected masks
+    bool mIgnoreMasks; 
 };
 
 // One function can bind to multiple Key options
diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h
index ef7f717b57..19576fb247 100644
--- a/indra/llui/llscrolllistcell.h
+++ b/indra/llui/llscrolllistcell.h
@@ -70,7 +70,7 @@ public:
 		Optional<LLColor4>			color;
 
 		Params()
-		:	type("cell_type", "text"), // Don't use "type", it overlaps with xml's parameter
+		:	type("type", "text"),
 			column("column"),
 			width("width"),
 			enabled("enabled", true),
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 8345d5c445..cbd2dd8b2f 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1666,7 +1666,7 @@ set(viewer_APPSETTINGS_FILES
     app_settings/grass.xml
     app_settings/high_graphics.xml
     app_settings/ignorable_dialogs.xml
-    app_settings/keys.xml
+    app_settings/key_bindings.xml
     app_settings/keywords_lsl_default.xml
     app_settings/logcontrol.xml
     app_settings/low_graphics.xml
diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml
new file mode 100644
index 0000000000..0c90ef26df
--- /dev/null
+++ b/indra/newview/app_settings/key_bindings.xml
@@ -0,0 +1,302 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<keys>
+  <first_person>
+    <binding key="A" mask="NONE" command="slide_left"/>
+    <binding key="D" mask="NONE" command="slide_right"/>
+    <binding key="W" mask="NONE" command="push_forward"/>
+    <binding key="S" mask="NONE" command="push_backward"/>
+    <binding key="E" mask="NONE" command="jump"/>
+    <binding key="C" mask="NONE" command="push_down"/>
+    <binding key="F" mask="NONE" command="toggle_fly"/>
+
+    <binding key="LEFT" mask="NONE" command="slide_left"/>
+    <binding key="RIGHT" mask="NONE" command="slide_right"/>
+    <binding key="UP" mask="NONE" command="push_forward"/>
+    <binding key="DOWN" mask="NONE" command="push_backward"/>
+    <binding key="PGUP" mask="NONE" command="jump"/>
+    <binding key="PGDN" mask="NONE" command="push_down"/>
+    <binding key="HOME" mask="NONE" command="toggle_fly"/>
+
+    <binding key="PAD_LEFT" mask="NONE" command="slide_left"/>
+    <binding key="PAD_RIGHT" mask="NONE" command="slide_right"/>
+    <binding key="PAD_UP" mask="NONE" command="push_forward"/>
+    <binding key="PAD_DOWN" mask="NONE" command="push_backward"/>
+    <binding key="PAD_PGUP" mask="NONE" command="jump"/>
+    <binding key="PAD_PGDN" mask="NONE" command="push_down"/>
+    <binding key="PAD_HOME" mask="NONE" command="toggle_fly"/>
+    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
+    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+
+    <binding key="SPACE" mask="NONE" command="stop_moving"/>
+    <binding key="ENTER" mask="NONE" command="start_chat"/>
+    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+  </first_person>
+  <third_person>
+    <binding key="A" mask="NONE" command="turn_left"/>
+    <binding key="D" mask="NONE" command="turn_right"/>
+    <binding key="A" mask="SHIFT" command="slide_left"/>
+    <binding key="D" mask="SHIFT" command="slide_right"/>
+    <binding key="W" mask="NONE" command="push_forward"/>
+    <binding key="S" mask="NONE" command="push_backward"/>
+    <binding key="E" mask="NONE" command="jump"/>
+    <binding key="C" mask="NONE" command="push_down"/>
+
+    <binding key="F" mask="NONE" command="toggle_fly"/>
+
+    <binding key="SPACE" mask="NONE" command="stop_moving"/>
+    <binding key="ENTER" mask="NONE" command="start_chat"/>
+    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+
+    <binding key="LEFT" mask="NONE" command="turn_left"/>
+    <binding key="LEFT" mask="SHIFT" command="slide_left"/>
+    <binding key="RIGHT" mask="NONE" command="turn_right"/>
+    <binding key="RIGHT" mask="SHIFT" command="slide_right"/>
+    <binding key="UP" mask="NONE" command="push_forward"/>
+    <binding key="DOWN" mask="NONE" command="push_backward"/>
+    <binding key="PGUP" mask="NONE" command="jump"/>
+    <binding key="PGDN" mask="NONE" command="push_down"/>
+    <binding key="HOME" mask="NONE" command="toggle_fly"/>
+
+    <binding key="PAD_LEFT" mask="NONE" command="turn_left"/>
+    <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
+    <binding key="PAD_RIGHT" mask="NONE" command="turn_right"/>
+    <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
+    <binding key="PAD_UP" mask="NONE" command="push_forward"/>
+    <binding key="PAD_DOWN" mask="NONE" command="push_backward"/>
+    <binding key="PAD_PGUP" mask="NONE" command="jump"/>
+    <binding key="PAD_PGDN" mask="NONE" command="push_down"/>
+    <binding key="PAD_HOME" mask="NONE" command="toggle_fly"/>
+    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
+    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+
+    <!--Camera controls in third person on Alt-->
+    <binding key="LEFT" mask="ALT" command="spin_around_cw"/>
+    <binding key="RIGHT" mask="ALT" command="spin_around_ccw"/>
+    <binding key="UP" mask="ALT" command="move_forward"/>
+    <binding key="DOWN" mask="ALT" command="move_backward"/>
+    <binding key="PGUP" mask="ALT" command="spin_over"/>
+    <binding key="PGDN" mask="ALT" command="spin_under"/>
+
+    <binding key="A" mask="ALT" command="spin_around_cw"/>
+    <binding key="D" mask="ALT" command="spin_around_ccw"/>
+    <binding key="W" mask="ALT" command="move_forward"/>
+    <binding key="S" mask="ALT" command="move_backward"/>
+    <binding key="E" mask="ALT" command="spin_over"/>
+    <binding key="C" mask="ALT" command="spin_under"/>
+
+    <binding key="PAD_LEFT" mask="ALT" command="spin_around_cw"/>
+    <binding key="PAD_RIGHT" mask="ALT" command="spin_around_ccw"/>
+    <binding key="PAD_UP" mask="ALT" command="move_forward"/>
+    <binding key="PAD_DOWN" mask="ALT" command="move_backward"/>
+    <binding key="PAD_PGUP" mask="ALT" command="spin_over"/>
+    <binding key="PAD_PGDN" mask="ALT" command="spin_under"/>
+    <binding key="PAD_ENTER" mask="ALT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/>
+
+    <!--mimic alt zoom behavior with keyboard only-->
+    <binding key="W" mask="CTL_ALT" command="spin_over"/>
+    <binding key="S" mask="CTL_ALT" command="spin_under"/>
+
+    <binding key="UP" mask="CTL_ALT" command="spin_over"/>
+    <binding key="DOWN" mask="CTL_ALT" command="spin_under"/>
+
+    <binding key="PAD_UP" mask="CTL_ALT" command="spin_over"/>
+    <binding key="PAD_DOWN" mask="CTL_ALT" command="spin_under"/>
+
+    <!--Therefore pan on Alt-Shift-->
+    <binding key="A" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="D" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="W" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="S" mask="CTL_ALT_SHIFT" command="pan_down"/>
+
+    <binding key="LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
+
+    <binding key="PAD_LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="PAD_RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="PAD_UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="PAD_DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
+    <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>
+  </third_person>
+
+  <!-- Basic editing camera control -->
+  <edit>
+    <binding key="A" mask="NONE" command="spin_around_cw"/>
+    <binding key="D" mask="NONE" command="spin_around_ccw"/>
+    <binding key="W" mask="NONE" command="move_forward"/>
+    <binding key="S" mask="NONE" command="move_backward"/>
+    <binding key="E" mask="NONE" command="spin_over"/>
+    <binding key="C" mask="NONE" command="spin_under"/>
+    <binding key="ENTER" mask="NONE" command="start_chat"/>
+    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+
+    <binding key="LEFT" mask="NONE" command="spin_around_cw"/>
+    <binding key="RIGHT" mask="NONE" command="spin_around_ccw"/>
+    <binding key="UP" mask="NONE" command="move_forward"/>
+    <binding key="DOWN" mask="NONE" command="move_backward"/>
+    <binding key="PGUP" mask="NONE" command="spin_over"/>
+    <binding key="PGDN" mask="NONE" command="spin_under"/>
+
+    <binding key="A" mask="SHIFT" command="pan_left"/>
+    <binding key="D" mask="SHIFT" command="pan_right"/>
+    <binding key="W" mask="SHIFT" command="pan_up"/>
+    <binding key="S" mask="SHIFT" command="pan_down"/>
+
+    <binding key="LEFT" mask="SHIFT" command="pan_left"/>
+    <binding key="RIGHT" mask="SHIFT" command="pan_right"/>
+    <binding key="UP" mask="SHIFT" command="pan_up"/>
+    <binding key="DOWN" mask="SHIFT" command="pan_down"/>
+
+    <!--Walking works with ALT held down.-->
+    <binding key="A" mask="ALT" command="slide_left"/>
+    <binding key="D" mask="ALT" command="slide_right"/>
+    <binding key="W" mask="ALT" command="push_forward"/>
+    <binding key="S" mask="ALT" command="push_backward"/>
+    <binding key="E" mask="ALT" command="jump"/>
+    <binding key="C" mask="ALT" command="push_down"/>
+
+    <binding key="LEFT" mask="ALT" command="slide_left"/>
+    <binding key="RIGHT" mask="ALT" command="slide_right"/>
+    <binding key="UP" mask="ALT" command="push_forward"/>
+    <binding key="DOWN" mask="ALT" command="push_backward"/>
+    <binding key="PGUP" mask="ALT" command="jump"/>
+    <binding key="PGDN" mask="ALT" command="push_down"/>
+    <binding key="HOME" mask="ALT" command="toggle_fly"/>
+
+    <binding key="PAD_LEFT" mask="ALT" command="slide_left"/>
+    <binding key="PAD_RIGHT" mask="ALT" command="slide_right"/>
+    <binding key="PAD_UP" mask="ALT" command="push_forward"/>
+    <binding key="PAD_DOWN" mask="ALT" command="push_backward"/>
+    <binding key="PAD_PGUP" mask="ALT" command="jump"/>
+    <binding key="PAD_PGDN" mask="ALT" command="push_down"/>
+    <binding key="PAD_ENTER" mask="ALT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/>
+  </edit>
+  <sitting>
+    <binding key="A" mask="ALT" command="spin_around_cw"/>
+    <binding key="D" mask="ALT" command="spin_around_ccw"/>
+    <binding key="W" mask="ALT" command="move_forward"/>
+    <binding key="S" mask="ALT" command="move_backward"/>
+    <binding key="E" mask="ALT" command="spin_over_sitting"/>
+    <binding key="C" mask="ALT" command="spin_under_sitting"/>
+
+    <binding key="LEFT" mask="ALT" command="spin_around_cw"/>
+    <binding key="RIGHT" mask="ALT" command="spin_around_ccw"/>
+    <binding key="UP" mask="ALT" command="move_forward"/>
+    <binding key="DOWN" mask="ALT" command="move_backward"/>
+    <binding key="PGUP" mask="ALT" command="spin_over"/>
+    <binding key="PGDN" mask="ALT" command="spin_under"/>
+
+    <binding key="W" mask="CTL_ALT" command="spin_over"/>
+    <binding key="S" mask="CTL_ALT" command="spin_under"/>
+    <binding key="E" mask="CTL_ALT" command="spin_over"/>
+    <binding key="C" mask="CTL_ALT" command="spin_under"/>
+
+    <binding key="UP" mask="CTL_ALT" command="spin_over"/>
+    <binding key="DOWN" mask="CTL_ALT" command="spin_under"/>
+    <binding key="PGUP" mask="CTL_ALT" command="spin_over"/>
+    <binding key="PGDN" mask="CTL_ALT" command="spin_under"/>
+
+
+    <binding key="A" mask="NONE" command="spin_around_cw_sitting"/>
+    <binding key="D" mask="NONE" command="spin_around_ccw_sitting"/>
+    <binding key="W" mask="NONE" command="move_forward_sitting"/>
+    <binding key="S" mask="NONE" command="move_backward_sitting"/>
+    <binding key="E" mask="NONE" command="spin_over_sitting"/>
+    <binding key="C" mask="NONE" command="spin_under_sitting"/>
+
+    <binding key="LEFT" mask="NONE" command="spin_around_cw_sitting"/>
+    <binding key="RIGHT" mask="NONE" command="spin_around_ccw_sitting"/>
+    <binding key="UP" mask="NONE" command="move_forward_sitting"/>
+    <binding key="DOWN" mask="NONE" command="move_backward_sitting"/>
+    <binding key="PGUP" mask="NONE" command="spin_over_sitting"/>
+    <binding key="PGDN" mask="NONE" command="spin_under_sitting"/>
+
+    <binding key="PAD_LEFT" mask="NONE" command="spin_around_cw_sitting"/>
+    <binding key="PAD_RIGHT" mask="NONE" command="spin_around_ccw_sitting"/>
+    <binding key="PAD_UP" mask="NONE" command="move_forward_sitting"/>
+    <binding key="PAD_DOWN" mask="NONE" command="move_backward_sitting"/>
+    <binding key="PAD_PGUP" mask="NONE" command="spin_over_sitting"/>
+    <binding key="PAD_PGDN" mask="NONE" command="spin_under_sitting"/>
+    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
+    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+
+    <!--these are for passing controls when sitting on vehicles-->
+    <binding key="A" mask="SHIFT" command="slide_left"/>
+    <binding key="D" mask="SHIFT" command="slide_right"/>
+    <binding key="W" mask="SHIFT" command="move_forward_sitting"/>
+    <binding key="S" mask="SHIFT" command="move_backward_sitting"/>
+    <binding key="E" mask="SHIFT" command="spin_over_sitting"/>
+    <binding key="C" mask="SHIFT" command="spin_under_sitting"/>
+
+    <binding key="LEFT" mask="SHIFT" command="slide_left"/>
+    <binding key="RIGHT" mask="SHIFT" command="slide_right"/>
+    <binding key="UP" mask="SHIFT" command="move_forward_sitting"/>
+    <binding key="DOWN" mask="SHIFT" command="move_backward_sitting"/>
+    <binding key="PGUP" mask="SHIFT" command="spin_over_sitting"/>
+    <binding key="PGDN" mask="SHIFT" command="spin_under_sitting"/>
+
+    <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
+    <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
+    <binding key="PAD_UP" mask="SHIFT" command="move_forward_sitting"/>
+    <binding key="PAD_DOWN" mask="SHIFT" command="move_backward_sitting"/>
+    <binding key="PAD_PGUP" mask="SHIFT" command="spin_over_sitting"/>
+    <binding key="PAD_PGDN" mask="SHIFT" command="spin_under_sitting"/> 
+    <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/>
+
+    <!--pan on Alt-Shift-->
+    <binding key="A" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="D" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="W" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="S" mask="CTL_ALT_SHIFT" command="pan_down"/>
+
+    <binding key="LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
+
+    <binding key="PAD_LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="PAD_RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="PAD_UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="PAD_DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
+    <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>
+
+    <binding key="ENTER" mask="NONE" command="start_chat"/>
+    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+  </sitting>
+  <edit_avatar>
+    <!--Avatar editing camera controls-->
+    <binding key="A" mask="NONE" command="edit_avatar_spin_cw"/>
+    <binding key="D" mask="NONE" command="edit_avatar_spin_ccw"/>
+    <binding key="W" mask="NONE" command="edit_avatar_move_forward"/>
+    <binding key="S" mask="NONE" command="edit_avatar_move_backward"/>
+    <binding key="E" mask="NONE" command="edit_avatar_spin_over"/>
+    <binding key="C" mask="NONE" command="edit_avatar_spin_under"/>
+    <binding key="LEFT" mask="NONE" command="edit_avatar_spin_cw"/>
+    <binding key="RIGHT" mask="NONE" command="edit_avatar_spin_ccw"/>
+    <binding key="UP" mask="NONE" command="edit_avatar_move_forward"/>
+    <binding key="DOWN" mask="NONE" command="edit_avatar_move_backward"/>
+    <binding key="PGUP" mask="NONE" command="edit_avatar_spin_over"/>
+    <binding key="PGDN" mask="NONE" command="edit_avatar_spin_under"/>
+    <binding key="ENTER" mask="NONE" command="start_chat"/>
+    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+    <binding key="PAD_LEFT" mask="NONE" command="edit_avatar_spin_cw"/>
+    <binding key="PAD_RIGHT" mask="NONE" command="edit_avatar_spin_ccw"/>
+    <binding key="PAD_UP" mask="NONE" command="edit_avatar_move_forward"/>
+    <binding key="PAD_DOWN" mask="NONE" command="edit_avatar_move_backward"/>
+    <binding key="PAD_PGUP" mask="NONE" command="edit_avatar_spin_over"/>
+    <binding key="PAD_PGDN" mask="NONE" command="edit_avatar_spin_under"/>
+    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+  </edit_avatar>
+</keys>
\ No newline at end of file
diff --git a/indra/newview/app_settings/keys.xml b/indra/newview/app_settings/keys.xml
deleted file mode 100644
index a8037fec05..0000000000
--- a/indra/newview/app_settings/keys.xml
+++ /dev/null
@@ -1,363 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<keys>
-  <first_person>
-    <binding key="A" mask="NONE" command="slide_left"/>
-    <binding key="D" mask="NONE" command="slide_right"/>
-    <binding key="W" mask="NONE" command="push_forward"/>
-    <binding key="S" mask="NONE" command="push_backward"/>
-    <binding key="E" mask="NONE" command="jump"/>
-    <binding key="C" mask="NONE" command="push_down"/>
-    <binding key="F" mask="NONE" command="toggle_fly"/>
-
-    <binding key="LEFT" mask="NONE" command="slide_left"/>
-    <binding key="RIGHT" mask="NONE" command="slide_right"/>
-    <binding key="UP" mask="NONE" command="push_forward"/>
-    <binding key="DOWN" mask="NONE" command="push_backward"/>
-    <binding key="PGUP" mask="NONE" command="jump"/>
-    <binding key="PGDN" mask="NONE" command="push_down"/>
-    <binding key="HOME" mask="NONE" command="toggle_fly"/>
-
-    <binding key="PAD_LEFT" mask="NONE" command="slide_left"/>
-    <binding key="PAD_RIGHT" mask="NONE" command="slide_right"/>
-    <binding key="PAD_UP" mask="NONE" command="push_forward"/>
-    <binding key="PAD_DOWN" mask="NONE" command="push_backward"/>
-    <binding key="PAD_PGUP" mask="NONE" command="jump"/>
-    <binding key="PAD_PGDN" mask="NONE" command="push_down"/>
-    <binding key="PAD_HOME" mask="NONE" command="toggle_fly"/>
-    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
-    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
-
-    <binding key="A" mask="SHIFT" command="slide_left"/>
-    <binding key="D" mask="SHIFT" command="slide_right"/>
-    <binding key="W" mask="SHIFT" command="push_forward"/>
-    <binding key="S" mask="SHIFT" command="push_backward"/>
-    <binding key="E" mask="SHIFT" command="jump"/>
-    <binding key="C" mask="SHIFT" command="push_down"/>
-    <binding key="F" mask="SHIFT" command="toggle_fly"/>
-
-    <binding key="SPACE" mask="NONE" command="stop_moving"/>
-    <binding key="ENTER" mask="NONE" command="start_chat"/>
-    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
-
-    <binding key="LEFT" mask="SHIFT" command="slide_left"/>
-    <binding key="RIGHT" mask="SHIFT" command="slide_right"/>
-    <binding key="UP" mask="SHIFT" command="push_forward"/>
-    <binding key="DOWN" mask="SHIFT" command="push_backward"/>
-    <binding key="PGUP" mask="SHIFT" command="jump"/>
-    <binding key="PGDN" mask="SHIFT" command="push_down"/>
-
-    <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
-    <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
-    <binding key="PAD_UP" mask="SHIFT" command="push_forward"/>
-    <binding key="PAD_DOWN" mask="SHIFT" command="push_backward"/>
-    <binding key="PAD_PGUP" mask="SHIFT" command="jump"/>
-    <binding key="PAD_PGDN" mask="SHIFT" command="push_down"/>
-    <binding key="PAD_HOME" mask="SHIFT" command="toggle_fly"/>
-    <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/>
-  </first_person>
-  <third_person>
-    <binding key="A" mask="NONE" command="turn_left"/>
-    <binding key="D" mask="NONE" command="turn_right"/>
-    <binding key="A" mask="SHIFT" command="slide_left"/>
-    <binding key="D" mask="SHIFT" command="slide_right"/>
-    <binding key="W" mask="NONE" command="push_forward"/>
-    <binding key="S" mask="NONE" command="push_backward"/>
-    <binding key="W" mask="SHIFT" command="push_forward"/>
-    <binding key="S" mask="SHIFT" command="push_backward"/>
-    <binding key="E" mask="NONE" command="jump"/>
-    <binding key="C" mask="NONE" command="push_down"/>
-    <binding key="E" mask="SHIFT" command="jump"/>
-    <binding key="C" mask="SHIFT" command="push_down"/>
-
-    <binding key="F" mask="NONE" command="toggle_fly"/>
-    <binding key="F" mask="SHIFT" command="toggle_fly"/>
-
-    <binding key="SPACE" mask="NONE" command="stop_moving"/>
-    <binding key="ENTER" mask="NONE" command="start_chat"/>
-    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
-
-    <binding key="LEFT" mask="NONE" command="turn_left"/>
-    <binding key="LEFT" mask="SHIFT" command="slide_left"/>
-    <binding key="RIGHT" mask="NONE" command="turn_right"/>
-    <binding key="RIGHT" mask="SHIFT" command="slide_right"/>
-    <binding key="UP" mask="NONE" command="push_forward"/>
-    <binding key="DOWN" mask="NONE" command="push_backward"/>
-    <binding key="UP" mask="SHIFT" command="push_forward"/>
-    <binding key="DOWN" mask="SHIFT" command="push_backward"/>
-    <binding key="PGUP" mask="NONE" command="jump"/>
-    <binding key="PGDN" mask="NONE" command="push_down"/>
-    <binding key="PGUP" mask="SHIFT" command="jump"/>
-    <binding key="PGDN" mask="SHIFT" command="push_down"/>
-    <binding key="HOME" mask="SHIFT" command="toggle_fly"/>
-    <binding key="HOME" mask="NONE" command="toggle_fly"/>
-
-    <binding key="PAD_LEFT" mask="NONE" command="turn_left"/>
-    <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
-    <binding key="PAD_RIGHT" mask="NONE" command="turn_right"/>
-    <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
-    <binding key="PAD_UP" mask="NONE" command="push_forward"/>
-    <binding key="PAD_DOWN" mask="NONE" command="push_backward"/>
-    <binding key="PAD_UP" mask="SHIFT" command="push_forward"/>
-    <binding key="PAD_DOWN" mask="SHIFT" command="push_backward"/>
-    <binding key="PAD_PGUP" mask="NONE" command="jump"/>
-    <binding key="PAD_PGDN" mask="NONE" command="push_down"/>
-    <binding key="PAD_PGUP" mask="SHIFT" command="jump"/>
-    <binding key="PAD_PGDN" mask="SHIFT" command="push_down"/>
-    <binding key="PAD_HOME" mask="NONE" command="toggle_fly"/>
-    <binding key="PAD_HOME" mask="SHIFT" command="toggle_fly"/>
-    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
-    <binding key="PAD_CENTER" mask="SHIFT" command="stop_moving"/>
-    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
-    <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
-    <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/>
-
-    <!--Camera controls in third person on Alt-->
-    <binding key="LEFT" mask="ALT" command="spin_around_cw"/>
-    <binding key="RIGHT" mask="ALT" command="spin_around_ccw"/>
-    <binding key="UP" mask="ALT" command="move_forward"/>
-    <binding key="DOWN" mask="ALT" command="move_backward"/>
-    <binding key="PGUP" mask="ALT" command="spin_over"/>
-    <binding key="PGDN" mask="ALT" command="spin_under"/>
-
-    <binding key="A" mask="ALT" command="spin_around_cw"/>
-    <binding key="D" mask="ALT" command="spin_around_ccw"/>
-    <binding key="W" mask="ALT" command="move_forward"/>
-    <binding key="S" mask="ALT" command="move_backward"/>
-    <binding key="E" mask="ALT" command="spin_over"/>
-    <binding key="C" mask="ALT" command="spin_under"/>
-
-    <binding key="PAD_LEFT" mask="ALT" command="spin_around_cw"/>
-    <binding key="PAD_RIGHT" mask="ALT" command="spin_around_ccw"/>
-    <binding key="PAD_UP" mask="ALT" command="move_forward"/>
-    <binding key="PAD_DOWN" mask="ALT" command="move_backward"/>
-    <binding key="PAD_PGUP" mask="ALT" command="spin_over"/>
-    <binding key="PAD_PGDN" mask="ALT" command="spin_under"/>
-    <binding key="PAD_ENTER" mask="ALT" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/>
-
-    <!--mimic alt zoom behavior with keyboard only-->
-    <binding key="A" mask="CTL_ALT" command="spin_around_cw"/>
-    <binding key="D" mask="CTL_ALT" command="spin_around_ccw"/>
-    <binding key="W" mask="CTL_ALT" command="spin_over"/>
-    <binding key="S" mask="CTL_ALT" command="spin_under"/>
-    <binding key="E" mask="CTL_ALT" command="spin_over"/>
-    <binding key="C" mask="CTL_ALT" command="spin_under"/>
-
-    <binding key="LEFT" mask="CTL_ALT" command="spin_around_cw"/>
-    <binding key="RIGHT" mask="CTL_ALT" command="spin_around_ccw"/>
-    <binding key="UP" mask="CTL_ALT" command="spin_over"/>
-    <binding key="DOWN" mask="CTL_ALT" command="spin_under"/>
-    <binding key="PGUP" mask="CTL_ALT" command="spin_over"/>
-    <binding key="PGDN" mask="CTL_ALT" command="spin_under"/>
-
-    <binding key="PAD_LEFT" mask="CTL_ALT" command="spin_around_cw"/>
-    <binding key="PAD_RIGHT" mask="CTL_ALT" command="spin_around_ccw"/>
-    <binding key="PAD_UP" mask="CTL_ALT" command="spin_over"/>
-    <binding key="PAD_DOWN" mask="CTL_ALT" command="spin_under"/>
-    <binding key="PAD_PGUP" mask="CTL_ALT" command="spin_over"/>
-    <binding key="PAD_PGDN" mask="CTL_ALT" command="spin_under"/>
-    <binding key="PAD_ENTER" mask="CTL_ALT" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="CTL_ALT" command="start_gesture"/>
-
-    <!--Therefore pan on Alt-Shift-->
-    <binding key="A" mask="CTL_ALT_SHIFT" command="pan_left"/>
-    <binding key="D" mask="CTL_ALT_SHIFT" command="pan_right"/>
-    <binding key="W" mask="CTL_ALT_SHIFT" command="pan_up"/>
-    <binding key="S" mask="CTL_ALT_SHIFT" command="pan_down"/>
-
-    <binding key="LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
-    <binding key="RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
-    <binding key="UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
-    <binding key="DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
-
-    <binding key="PAD_LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
-    <binding key="PAD_RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
-    <binding key="PAD_UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
-    <binding key="PAD_DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
-    <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>
-  </third_person>
-
-  <!-- Basic editing camera control -->
-  <edit>
-    <binding key="A" mask="NONE" command="spin_around_cw"/>
-    <binding key="D" mask="NONE" command="spin_around_ccw"/>
-    <binding key="W" mask="NONE" command="move_forward"/>
-    <binding key="S" mask="NONE" command="move_backward"/>
-    <binding key="E" mask="NONE" command="spin_over"/>
-    <binding key="C" mask="NONE" command="spin_under"/>
-    <binding key="ENTER" mask="NONE" command="start_chat"/>
-    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
-    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
-
-    <binding key="LEFT" mask="NONE" command="spin_around_cw"/>
-    <binding key="RIGHT" mask="NONE" command="spin_around_ccw"/>
-    <binding key="UP" mask="NONE" command="move_forward"/>
-    <binding key="DOWN" mask="NONE" command="move_backward"/>
-    <binding key="PGUP" mask="NONE" command="spin_over"/>
-    <binding key="PGDN" mask="NONE" command="spin_under"/>
-
-    <binding key="A" mask="SHIFT" command="pan_left"/>
-    <binding key="D" mask="SHIFT" command="pan_right"/>
-    <binding key="W" mask="SHIFT" command="pan_up"/>
-    <binding key="S" mask="SHIFT" command="pan_down"/>
-
-    <binding key="LEFT" mask="SHIFT" command="pan_left"/>
-    <binding key="RIGHT" mask="SHIFT" command="pan_right"/>
-    <binding key="UP" mask="SHIFT" command="pan_up"/>
-    <binding key="DOWN" mask="SHIFT" command="pan_down"/>
-
-    <!--Walking works with ALT held down.-->
-    <binding key="A" mask="ALT" command="slide_left"/>
-    <binding key="D" mask="ALT" command="slide_right"/>
-    <binding key="W" mask="ALT" command="push_forward"/>
-    <binding key="S" mask="ALT" command="push_backward"/>
-    <binding key="E" mask="ALT" command="jump"/>
-    <binding key="C" mask="ALT" command="push_down"/>
-
-    <binding key="LEFT" mask="ALT" command="slide_left"/>
-    <binding key="RIGHT" mask="ALT" command="slide_right"/>
-    <binding key="UP" mask="ALT" command="push_forward"/>
-    <binding key="DOWN" mask="ALT" command="push_backward"/>
-    <binding key="PGUP" mask="ALT" command="jump"/>
-    <binding key="PGDN" mask="ALT" command="push_down"/>
-    <binding key="HOME" mask="ALT" command="toggle_fly"/>
-
-    <binding key="PAD_LEFT" mask="ALT" command="slide_left"/>
-    <binding key="PAD_RIGHT" mask="ALT" command="slide_right"/>
-    <binding key="PAD_UP" mask="ALT" command="push_forward"/>
-    <binding key="PAD_DOWN" mask="ALT" command="push_backward"/>
-    <binding key="PAD_PGUP" mask="ALT" command="jump"/>
-    <binding key="PAD_PGDN" mask="ALT" command="push_down"/>
-    <binding key="PAD_ENTER" mask="ALT" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/>
-  </edit>
-  <sitting>
-    <binding key="A" mask="ALT" command="spin_around_cw"/>
-    <binding key="D" mask="ALT" command="spin_around_ccw"/>
-    <binding key="W" mask="ALT" command="move_forward"/>
-    <binding key="S" mask="ALT" command="move_backward"/>
-    <binding key="E" mask="ALT" command="spin_over_sitting"/>
-    <binding key="C" mask="ALT" command="spin_under_sitting"/>
-
-    <binding key="LEFT" mask="ALT" command="spin_around_cw"/>
-    <binding key="RIGHT" mask="ALT" command="spin_around_ccw"/>
-    <binding key="UP" mask="ALT" command="move_forward"/>
-    <binding key="DOWN" mask="ALT" command="move_backward"/>
-    <binding key="PGUP" mask="ALT" command="spin_over"/>
-    <binding key="PGDN" mask="ALT" command="spin_under"/>
-
-    <binding key="A" mask="CTL_ALT" command="spin_around_cw"/>
-    <binding key="D" mask="CTL_ALT" command="spin_around_ccw"/>
-    <binding key="W" mask="CTL_ALT" command="spin_over"/>
-    <binding key="S" mask="CTL_ALT" command="spin_under"/>
-    <binding key="E" mask="CTL_ALT" command="spin_over"/>
-    <binding key="C" mask="CTL_ALT" command="spin_under"/>
-
-    <binding key="LEFT" mask="CTL_ALT" command="spin_around_cw"/>
-    <binding key="RIGHT" mask="CTL_ALT" command="spin_around_ccw"/>
-    <binding key="UP" mask="CTL_ALT" command="spin_over"/>
-    <binding key="DOWN" mask="CTL_ALT" command="spin_under"/>
-    <binding key="PGUP" mask="CTL_ALT" command="spin_over"/>
-    <binding key="PGDN" mask="CTL_ALT" command="spin_under"/>
-
-
-    <binding key="A" mask="NONE" command="spin_around_cw_sitting"/>
-    <binding key="D" mask="NONE" command="spin_around_ccw_sitting"/>
-    <binding key="W" mask="NONE" command="move_forward_sitting"/>
-    <binding key="S" mask="NONE" command="move_backward_sitting"/>
-    <binding key="E" mask="NONE" command="spin_over_sitting"/>
-    <binding key="C" mask="NONE" command="spin_under_sitting"/>
-
-    <binding key="LEFT" mask="NONE" command="spin_around_cw_sitting"/>
-    <binding key="RIGHT" mask="NONE" command="spin_around_ccw_sitting"/>
-    <binding key="UP" mask="NONE" command="move_forward_sitting"/>
-    <binding key="DOWN" mask="NONE" command="move_backward_sitting"/>
-    <binding key="PGUP" mask="NONE" command="spin_over_sitting"/>
-    <binding key="PGDN" mask="NONE" command="spin_under_sitting"/>
-
-    <binding key="PAD_LEFT" mask="NONE" command="spin_around_cw_sitting"/>
-    <binding key="PAD_RIGHT" mask="NONE" command="spin_around_ccw_sitting"/>
-    <binding key="PAD_UP" mask="NONE" command="move_forward_sitting"/>
-    <binding key="PAD_DOWN" mask="NONE" command="move_backward_sitting"/>
-    <binding key="PAD_PGUP" mask="NONE" command="spin_over_sitting"/>
-    <binding key="PAD_PGDN" mask="NONE" command="spin_under_sitting"/>
-    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
-    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
-
-    <!--these are for passing controls when sitting on vehicles-->
-    <binding key="A" mask="SHIFT" command="slide_left"/>
-    <binding key="D" mask="SHIFT" command="slide_right"/>
-    <binding key="W" mask="SHIFT" command="move_forward_sitting"/>
-	<binding key="S" mask="SHIFT" command="move_backward_sitting"/>
-	<binding key="E" mask="SHIFT" command="spin_over_sitting"/>
-	<binding key="C" mask="SHIFT" command="spin_under_sitting"/>
-
-    <binding key="LEFT" mask="SHIFT" command="slide_left"/>
-    <binding key="RIGHT" mask="SHIFT" command="slide_right"/>
-    <binding key="UP" mask="SHIFT" command="move_forward_sitting"/>
-	<binding key="DOWN" mask="SHIFT" command="move_backward_sitting"/>
-	<binding key="PGUP" mask="SHIFT" command="spin_over_sitting"/>
-	<binding key="PGDN" mask="SHIFT" command="spin_under_sitting"/>
-
-    <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
-    <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
-    <binding key="PAD_UP" mask="SHIFT" command="move_forward_sitting"/>
-	<binding key="PAD_DOWN" mask="SHIFT" command="move_backward_sitting"/>
-	<binding key="PAD_PGUP" mask="SHIFT" command="spin_over_sitting"/>
-	<binding key="PAD_PGDN" mask="SHIFT" command="spin_under_sitting"/> 
-    <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/>
-
-    <!--pan on Alt-Shift-->
-    <binding key="A" mask="CTL_ALT_SHIFT" command="pan_left"/>
-    <binding key="D" mask="CTL_ALT_SHIFT" command="pan_right"/>
-    <binding key="W" mask="CTL_ALT_SHIFT" command="pan_up"/>
-    <binding key="S" mask="CTL_ALT_SHIFT" command="pan_down"/>
-
-    <binding key="LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
-    <binding key="RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
-    <binding key="UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
-    <binding key="DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
-
-    <binding key="PAD_LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
-    <binding key="PAD_RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
-    <binding key="PAD_UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
-    <binding key="PAD_DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
-    <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>
-
-    <binding key="ENTER" mask="NONE" command="start_chat"/>
-    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
-  </sitting>
-  <edit_avatar>
-    <!--Avatar editing camera controls-->
-    <binding key="A" mask="NONE" command="edit_avatar_spin_cw"/>
-    <binding key="D" mask="NONE" command="edit_avatar_spin_ccw"/>
-    <binding key="W" mask="NONE" command="edit_avatar_move_forward"/>
-    <binding key="S" mask="NONE" command="edit_avatar_move_backward"/>
-    <binding key="E" mask="NONE" command="edit_avatar_spin_over"/>
-    <binding key="C" mask="NONE" command="edit_avatar_spin_under"/>
-    <binding key="LEFT" mask="NONE" command="edit_avatar_spin_cw"/>
-    <binding key="RIGHT" mask="NONE" command="edit_avatar_spin_ccw"/>
-    <binding key="UP" mask="NONE" command="edit_avatar_move_forward"/>
-    <binding key="DOWN" mask="NONE" command="edit_avatar_move_backward"/>
-    <binding key="PGUP" mask="NONE" command="edit_avatar_spin_over"/>
-    <binding key="PGDN" mask="NONE" command="edit_avatar_spin_under"/>
-    <binding key="ENTER" mask="NONE" command="start_chat"/>
-    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
-    <binding key="PAD_LEFT" mask="NONE" command="edit_avatar_spin_cw"/>
-    <binding key="PAD_RIGHT" mask="NONE" command="edit_avatar_spin_ccw"/>
-    <binding key="PAD_UP" mask="NONE" command="edit_avatar_move_forward"/>
-    <binding key="PAD_DOWN" mask="NONE" command="edit_avatar_move_backward"/>
-    <binding key="PAD_PGUP" mask="NONE" command="edit_avatar_spin_over"/>
-    <binding key="PAD_PGDN" mask="NONE" command="edit_avatar_spin_under"/>
-    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
-  </edit_avatar>
-</keys>
\ No newline at end of file
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 1023a553f8..96e77410c3 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1005,11 +1005,11 @@ bool LLAppViewer::init()
 	gGLManager.printGLInfoString();
 
 	// Load User's bindings
-	std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "keys.xml");
+	std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml");
 	if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file))
 	{
 		// Failed to load custom bindings, try default ones
-		key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "keys.xml");
+		key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "key_bindings.xml");
 		if (!gViewerInput.loadBindingsXML(key_bindings_file))
 		{
 			LL_ERRS("InitInfo") << "Unable to open default key bindings from" << key_bindings_file << LL_ENDL;
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 6ee1bbee1a..61fd13f219 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2926,7 +2926,7 @@ void LLPanelPreferenceControls::onListCommit()
         {
             mEditingControl = control;
             mEditingColumn = cell_ind;
-            dialog->setParent(this, DEFAULT_KEY_FILTER);
+            dialog->setParent(this, pControlsTable, DEFAULT_KEY_FILTER);
 
             LLFloater* root_floater = gFloaterView->getParentFloater(this);
             if (root_floater)
@@ -2946,6 +2946,14 @@ void LLPanelPreferenceControls::onModeCommit()
     regenerateControls();
 }
 
+void LLPanelPreferenceControls::onRestoreDefaults()
+{
+    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
+    {
+        mConflictHandler[mEditingMode].resetToDefaults();
+    }
+}
+
 // todo: copy onSetKeyBind to interface and inherit from interface
 bool LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore_mask)
 {
@@ -2956,21 +2964,13 @@ bool LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MAS
 
     if ( mEditingColumn > 0)
     {
-        mConflictHandler[mEditingMode].registerControl(mEditingControl, mEditingColumn - 1, click, key, mask, ignore_mask);
+        mConflictHandler[mEditingMode].registerControl(mEditingControl, mEditingColumn - 1, click, key, mask, true);
     }
 
     updateTable();
     return true;
 }
 
-void LLPanelPreferenceControls::onRestoreDefaults()
-{
-    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
-    {
-        mConflictHandler[mEditingMode].resetToDefaults();
-    }
-}
-
 void LLPanelPreferenceControls::onDefaultKeyBind()
 {
     if (!mConflictHandler[mEditingMode].canAssignControl(mEditingControl))
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 9734ea30a2..bc19564bf6 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -291,7 +291,7 @@ class LLPanelPreferenceControls : public LLPanelPreference, public LLKeyBindResp
 	LOG_CLASS(LLPanelPreferenceControls);
 public:
 	LLPanelPreferenceControls();
-	~LLPanelPreferenceControls();
+	virtual ~LLPanelPreferenceControls();
 
 	BOOL postBuild();
 
@@ -302,10 +302,10 @@ public:
 
 	void onListCommit();
 	void onModeCommit();
-	bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore_mask);
 	void onRestoreDefaults();
-	void onDefaultKeyBind();
-	void onCancelKeyBind();
+	/*virtual*/ bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore_mask);
+	/*virtual*/ void onDefaultKeyBind();
+	/*virtual*/ void onCancelKeyBind();
 
 private:
 	void regenerateControls();
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index bad4e4a2d8..0b9aaea478 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -243,10 +243,6 @@ std::string LLKeyConflictHandler::getStringFromKeyData(const LLKeyData& keydata)
     {
         result = LLKeyboard::stringFromAccelerator(keydata.mMask);
     }
-    else if (keydata.mIgnoreMasks)
-    {
-        result = "acc+";
-    }
 
     result += string_from_mouse(keydata.mMouse);
 
@@ -283,7 +279,6 @@ void LLKeyConflictHandler::loadFromSettings(const LLViewerInput::KeyMode& keymod
         KEY key;
         MASK mask;
         EMouseClickType mouse = it->mouse.isProvided() ? mouse_from_string(it->mouse) : CLICK_NONE;
-        bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;
         if (it->key.getValue().empty())
         {
             key = KEY_NONE;
@@ -297,7 +292,7 @@ void LLKeyConflictHandler::loadFromSettings(const LLViewerInput::KeyMode& keymod
         // might not know all the commands, so UI will have to know what to fill by its own
         LLKeyConflict &type_data = (*destination)[it->command];
         type_data.mAssignable = true;
-        type_data.mKeyBind.addKeyData(mouse, key, mask, ignore);
+        type_data.mKeyBind.addKeyData(mouse, key, mask, true);
     }
 }
 
@@ -380,7 +375,7 @@ void LLKeyConflictHandler::loadFromSettings(ESourceMode load_mode)
     else
     {
         // load defaults
-        std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "keys.xml");
+        std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "key_bindings.xml");
         if (!loadFromSettings(load_mode, filename, &mDefaultsMap))
         {
             LL_WARNS() << "Failed to load default settings, aborting" << LL_ENDL;
@@ -388,7 +383,7 @@ void LLKeyConflictHandler::loadFromSettings(ESourceMode load_mode)
         }
 
         // load user's
-        filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "keys.xml");
+        filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml");
         if (!gDirUtilp->fileExists(filename) || loadFromSettings(load_mode, filename, &mControlsMap))
         {
             // mind placeholders
@@ -440,7 +435,7 @@ void LLKeyConflictHandler::saveToSettings()
     else
     {
         // loaded full copy of original file
-        std::string filename = gDirUtilp->findFile("keys.xml",
+        std::string filename = gDirUtilp->findFile("key_bindings.xml",
             gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
             gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
 
@@ -494,7 +489,6 @@ void LLKeyConflictHandler::saveToSettings()
                     }
                     binding.mask = string_from_mask(data.mMask);
                     binding.mouse.set(string_from_mouse(data.mMouse), true); //set() because 'optional', for compatibility purposes
-                    binding.ignore.set(data.mIgnoreMasks, true);
                     binding.command = iter->first;
                     mode.bindings.add(binding);
                 }
@@ -537,7 +531,7 @@ void LLKeyConflictHandler::saveToSettings()
             }
 
             // write back to user's xml;
-            std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "keys.xml");
+            std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml");
 
             LLXMLNodePtr output_node = new LLXMLNode("keys", false);
             LLXUIParser parser;
@@ -708,7 +702,7 @@ void LLKeyConflictHandler::clear()
 
 void LLKeyConflictHandler::resetKeyboardBindings()
 {
-    std::string filename = gDirUtilp->findFile("keys.xml",
+    std::string filename = gDirUtilp->findFile("key_bindings.xml",
         gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
         gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
     
diff --git a/indra/newview/llpanelpresetspulldown.cpp b/indra/newview/llpanelpresetspulldown.cpp
index 1a49cbc250..0ca4a83779 100644
--- a/indra/newview/llpanelpresetspulldown.cpp
+++ b/indra/newview/llpanelpresetspulldown.cpp
@@ -33,6 +33,7 @@
 
 #include "llbutton.h"
 #include "lltabcontainer.h"
+#include "llfloater.h"
 #include "llfloaterreg.h"
 #include "llpresetsmanager.h"
 #include "llsliderctrl.h"
diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp
index 0ad71cb372..320f1f297d 100644
--- a/indra/newview/llsetkeybinddialog.cpp
+++ b/indra/newview/llsetkeybinddialog.cpp
@@ -34,6 +34,7 @@
 #include "llcheckboxctrl.h"
 #include "lleventtimer.h"
 #include "llfocusmgr.h"
+#include "llkeyconflict.h"
 
 class LLSetKeyBindDialog::Updater : public LLEventTimer
 {
@@ -85,6 +86,7 @@ BOOL LLSetKeyBindDialog::postBuild()
     getChild<LLUICtrl>("Cancel")->setFocus(TRUE);
 
     pCheckBox = getChild<LLCheckBoxCtrl>("ignore_masks");
+    pDesription = getChild<LLTextBase>("descritption");
 
     gFocusMgr.setKeystrokesOnly(TRUE);
 
@@ -116,14 +118,12 @@ void LLSetKeyBindDialog::draw()
     LLModalDialog::draw();
 }
 
-void LLSetKeyBindDialog::setParent(LLPanelPreferenceControls* parent, U32 key_mask)
+void LLSetKeyBindDialog::setParent(LLKeyBindResponderInterface* parent, LLView* frustum_origin, U32 key_mask)
 {
     pParent = parent;
-    setFrustumOrigin(parent);
+    setFrustumOrigin(frustum_origin);
     mKeyFilterMask = key_mask;
 
-    LLTextBase *text_ctrl = getChild<LLTextBase>("descritption");
-
     std::string input;
     if ((key_mask & ALLOW_MOUSE) != 0)
     {
@@ -137,7 +137,8 @@ void LLSetKeyBindDialog::setParent(LLPanelPreferenceControls* parent, U32 key_ma
         }
         input += getString("keyboard");
     }
-    text_ctrl->setTextArg("[INPUT]", input);
+    pDesription->setText(getString("basic_description"));
+    pDesription->setTextArg("[INPUT]", input);
 
     bool can_ignore_masks = (key_mask & CAN_IGNORE_MASKS) != 0;
     pCheckBox->setVisible(can_ignore_masks);
@@ -185,6 +186,13 @@ BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
         return FALSE;
     }
 
+    if (LLKeyConflictHandler::isReservedByMenu(key, mask))
+    {
+        pDesription->setText(getString("reserved_by_menu"));
+        pDesription->setTextArg("[KEYSTR]", LLKeyboard::stringFromAccelerator(mask,key));
+        return TRUE;
+    }
+
     setKeyBind(CLICK_NONE, key, mask, pCheckBox->getValue().asBoolean());
     closeFloater();
     return TRUE;
diff --git a/indra/newview/llsetkeybinddialog.h b/indra/newview/llsetkeybinddialog.h
index fb3b2a2269..8faa2cc363 100644
--- a/indra/newview/llsetkeybinddialog.h
+++ b/indra/newview/llsetkeybinddialog.h
@@ -32,6 +32,7 @@
 #include "lldrawfrustum.h"
 
 class LLCheckBoxCtrl;
+class LLTextBase;
 
 // Filters for LLSetKeyBindDialog
 static const U32 ALLOW_MOUSE = 1;
@@ -40,18 +41,18 @@ static const U32 ALLOW_KEYS = 4; //keyboard
 static const U32 ALLOW_MASK_KEYS = 8;
 static const U32 ALLOW_MASKS = 16;
 static const U32 CAN_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 | CAN_IGNORE_MASKS;
+static const U32 DEFAULT_KEY_FILTER = ALLOW_MOUSE | ALLOW_MASK_MOUSE | ALLOW_KEYS | ALLOW_MASK_KEYS;
 
 
 class LLKeyBindResponderInterface
 {
 public:
-    virtual ~LLKeyBindResponderInterface();
+    virtual ~LLKeyBindResponderInterface() {};
 
-    virtual void onCancelKeyBind();
-    virtual void onDefaultKeyBind();
+    virtual void onCancelKeyBind() = 0;
+    virtual void onDefaultKeyBind() = 0;
     // returns true if parent failed to set key due to key being in use
-    virtual bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore);
+    virtual bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore) = 0;
 };
 
 class LLSetKeyBindDialog : public LLModalDialog, public LLDrawFrustum
@@ -64,7 +65,7 @@ public:
     /*virtual*/ void onClose(bool app_quiting);
     /*virtual*/ void draw();
 
-    void setParent(LLKeyBindResponderInterface* parent, U32 key_mask = DEFAULT_KEY_FILTER);
+    void setParent(LLKeyBindResponderInterface* parent, LLView* frustum_origin, U32 key_mask = DEFAULT_KEY_FILTER);
 
     BOOL handleKeyHere(KEY key, MASK mask);
     BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down);
@@ -77,8 +78,9 @@ public:
 
 private:
     void setKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore);
-    LLKeyBindResponderInterface* pParent;
-    LLCheckBoxCtrl* pCheckBox;
+    LLKeyBindResponderInterface *pParent;
+    LLCheckBoxCtrl *pCheckBox;
+    LLTextBase *pDesription;
 
     U32 mKeyFilterMask;
     Updater *pUpdater;
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index eff578cf26..95c26cdde2 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -1005,7 +1005,7 @@ BOOL LLViewerInput::handleKeyUp(KEY translated_key, MASK translated_mask)
 	return gViewerWindow->handleKeyUp(translated_key, translated_mask);
 }
 
-BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, const bool ignore, const std::string& function_name)
+BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name)
 {
 	S32 index;
 	typedef boost::function<bool(EKeystate)> function_t;
@@ -1046,57 +1046,30 @@ BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, cons
 	}
 
 	// check for duplicate first and overwrite
-    if (ignore)
+    S32 size = mKeyBindings[mode].size();
+    for (index = 0; index < size; index++)
     {
-        for (index = 0; index < mKeyIgnoreMaskCount[mode]; index++)
-        {
-            if (key == mKeyIgnoreMask[mode][index].mKey)
-                break;
-        }
-    }
-    else
-    {
-        for (index = 0; index < mKeyBindingCount[mode]; index++)
-        {
-            if (key == mKeyBindings[mode][index].mKey && mask == mKeyBindings[mode][index].mMask)
-                break;
-        }
+        if (key == mKeyBindings[mode][index].mKey && mask == mKeyBindings[mode][index].mMask)
+            break;
     }
 
-	if (index >= MAX_KEY_BINDINGS)
-	{
-		LL_ERRS() << "LLKeyboard::bindKey() - too many keys for mode " << mode << LL_ENDL;
-		return FALSE;
-	}
-
 	if (mode >= MODE_COUNT)
 	{
 		LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
 		return FALSE;
 	}
 
-    if (ignore)
-    {
-        mKeyIgnoreMask[mode][index].mKey = key;
-        mKeyIgnoreMask[mode][index].mFunction = function;
-
-        if (index == mKeyIgnoreMaskCount[mode])
-            mKeyIgnoreMaskCount[mode]++;
-    }
-    else
-    {
-        mKeyBindings[mode][index].mKey = key;
-        mKeyBindings[mode][index].mMask = mask;
-        mKeyBindings[mode][index].mFunction = function;
+    LLKeyboardBinding bind;
+    bind.mKey = key;
+    bind.mMask = mask;
+    bind.mFunction = function;
 
-        if (index == mKeyBindingCount[mode])
-            mKeyBindingCount[mode]++;
-    }
+    mKeyBindings[mode].push_back(bind);
 
 	return TRUE;
 }
 
-BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const bool ignore, const std::string& function_name)
+BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const std::string& function_name)
 {
     S32 index;
     typedef boost::function<bool(EKeystate)> function_t;
@@ -1115,27 +1088,11 @@ BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const
     }
 
     // check for duplicate first and overwrite
-    if (ignore)
-    {
-        for (index = 0; index < mMouseIgnoreMaskCount[mode]; index++)
-        {
-            if (mouse == mMouseIgnoreMask[mode][index].mMouse)
-                break;
-        }
-    }
-    else
-    {
-        for (index = 0; index < mMouseBindingCount[mode]; index++)
-        {
-            if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask)
-                break;
-        }
-    }
-
-    if (index >= MAX_KEY_BINDINGS)
+    S32 size = mMouseBindings[mode].size();
+    for (index = 0; index < size; index++)
     {
-        LL_ERRS() << "LLKeyboard::bindKey() - too many keys for mode " << mode << LL_ENDL;
-        return FALSE;
+        if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask)
+            break;
     }
 
     if (mode >= MODE_COUNT)
@@ -1144,23 +1101,12 @@ BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const
         return FALSE;
     }
 
-    if (ignore)
-    {
-        mMouseIgnoreMask[mode][index].mMouse = mouse;
-        mMouseIgnoreMask[mode][index].mFunction = function;
-
-        if (index == mMouseIgnoreMaskCount[mode])
-            mMouseIgnoreMaskCount[mode]++;
-    }
-    else
-    {
-        mMouseBindings[mode][index].mMouse = mouse;
-        mMouseBindings[mode][index].mMask = mask;
-        mMouseBindings[mode][index].mFunction = function;
+    LLMouseBinding bind;
+    bind.mMouse = mouse;
+    bind.mMask = mask;
+    bind.mFunction = function;
 
-        if (index == mMouseBindingCount[mode])
-            mMouseBindingCount[mode]++;
-    }
+    mMouseBindings[mode].push_back(bind);
 
     return TRUE;
 }
@@ -1169,8 +1115,7 @@ LLViewerInput::KeyBinding::KeyBinding()
 :	key("key"),
 	mouse("mouse"),
 	mask("mask"),
-	command("command"),
-	ignore("ignore", false)
+	command("command")
 {}
 
 LLViewerInput::KeyMode::KeyMode()
@@ -1189,10 +1134,8 @@ void LLViewerInput::resetBindings()
 {
     for (S32 i = 0; i < MODE_COUNT; i++)
     {
-        mKeyBindingCount[i] = 0;
-        mKeyIgnoreMaskCount[i] = 0;
-        mMouseBindingCount[i] = 0;
-        mMouseIgnoreMaskCount[i] = 0;
+        mKeyBindings[i].clear();
+        mMouseBindings[i].clear();
     }
 }
 
@@ -1216,6 +1159,34 @@ S32 LLViewerInput::loadBindingsXML(const std::string& filename)
 	return binding_count;
 }
 
+S32 count_masks(const MASK &mask)
+{
+    S32 res = 0;
+    if (mask & MASK_CONTROL)
+    {
+        res++;
+    }
+    if (mask & MASK_SHIFT)
+    {
+        res++;
+    }
+    if (mask & MASK_ALT)
+    {
+        res++;
+    }
+    return res;
+}
+
+bool compare_key_by_mask(LLKeyboardBinding i1, LLKeyboardBinding i2)
+{
+    return (count_masks(i1.mMask) > count_masks(i2.mMask));
+}
+
+bool compare_mouse_by_mask(LLMouseBinding i1, LLMouseBinding i2)
+{
+    return (count_masks(i1.mMask) > count_masks(i2.mMask));
+}
+
 S32 LLViewerInput::loadBindingMode(const LLViewerInput::KeyMode& keymode, S32 mode)
 {
 	S32 binding_count = 0;
@@ -1232,9 +1203,8 @@ S32 LLViewerInput::loadBindingMode(const LLViewerInput::KeyMode& keymode, S32 mo
             if (key != KEY_NONE)
             {
                 MASK mask;
-                bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;
                 LLKeyboard::maskFromString(it->mask, &mask);
-                bindKey(mode, key, mask, ignore, it->command);
+                bindKey(mode, key, mask, it->command);
                 processed = true;
             }
             else
@@ -1249,9 +1219,8 @@ S32 LLViewerInput::loadBindingMode(const LLViewerInput::KeyMode& keymode, S32 mo
             if (mouse != CLICK_NONE)
             {
                 MASK mask;
-                bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;
                 LLKeyboard::maskFromString(it->mask, &mask);
-                bindMouse(mode, mouse, mask, ignore, it->command);
+                bindMouse(mode, mouse, mask, it->command);
                 processed = true;
             }
             else
@@ -1264,7 +1233,11 @@ S32 LLViewerInput::loadBindingMode(const LLViewerInput::KeyMode& keymode, S32 mo
             // total
             binding_count++;
         }
-	}
+    }
+
+    // sort lists by mask (so that Shift+W is executed before W, if both are assigned, but if Shift+W is not assigned W should be executed)
+    std::sort(mKeyBindings[mode].begin(), mKeyBindings[mode].end(), compare_key_by_mask);
+    std::sort(mMouseBindings[mode].begin(), mMouseBindings[mode].end(), compare_mouse_by_mask);
 
 	return binding_count;
 }
@@ -1289,7 +1262,7 @@ EKeyboardMode LLViewerInput::getMode() const
 	}
 }
 
-bool LLViewerInput::scanKey(const LLKeyboardBinding* binding,
+bool LLViewerInput::scanKey(const std::vector<LLKeyboardBinding> &binding,
                                S32 binding_count,
                                KEY key,
                                MASK mask,
@@ -1302,7 +1275,7 @@ bool LLViewerInput::scanKey(const LLKeyboardBinding* binding,
 	{
 		if (binding[i].mKey == key)
 		{
-			if (binding[i].mMask == mask)
+			if ((binding[i].mMask & mask) == binding[i].mMask)
 			{
 				bool res = false;
 				if (key_down && !repeat)
@@ -1350,12 +1323,7 @@ bool LLViewerInput::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
 	// don't process key down on repeated keys
 	BOOL repeat = gKeyboard->getKeyRepeated(key);
 
-    bool res = scanKey(mKeyBindings[mode], mKeyBindingCount[mode], key, mask, key_down, key_up, key_level, repeat);
-    if (!res)
-    {
-        // Nothing found, try ignore list
-        res = scanKey(mKeyIgnoreMask[mode], mKeyIgnoreMaskCount[mode], key, MASK_NONE, key_down, key_up, key_level, repeat);
-    }
+    bool res = scanKey(mKeyBindings[mode], mKeyBindings[mode].size(), key, mask, key_down, key_up, key_level, repeat);
 
     if (!res && agent_control_lbutton.canHandle(CLICK_NONE, key, mask))
     {
@@ -1443,11 +1411,11 @@ BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask,
     return handled;
 }
 
-bool LLViewerInput::scanMouse(const LLMouseBinding *binding, S32 binding_count, EMouseClickType mouse, MASK mask, EMouseState state) const
+bool LLViewerInput::scanMouse(const std::vector<LLMouseBinding> &binding, S32 binding_count, EMouseClickType mouse, MASK mask, EMouseState state) const
 {
     for (S32 i = 0; i < binding_count; i++)
     {
-        if (binding[i].mMouse == mouse && binding[i].mMask == mask)
+        if (binding[i].mMouse == mouse && (binding[i].mMask & mask) == binding[i].mMask)
         {
             bool res = false;
             switch (state)
@@ -1484,11 +1452,7 @@ bool LLViewerInput::scanMouse(EMouseClickType click, EMouseState state) const
     bool res = false;
     S32 mode = getMode();
     MASK mask = gKeyboard->currentMask(TRUE);
-    res = scanMouse(mMouseBindings[mode], mMouseBindingCount[mode], click, mask, state);
-    if (!res)
-    {
-        res = scanMouse(mMouseIgnoreMask[mode], mMouseIgnoreMaskCount[mode], click, MASK_NONE, state);
-    }
+    res = scanMouse(mMouseBindings[mode], mMouseBindings[mode].size(), click, mask, state);
     // no user defined actions found or those actions can't handle the key/button, handle control if nessesary
     if (!res && agent_control_lbutton.canHandle(click, KEY_NONE, mask))
     {
diff --git a/indra/newview/llviewerinput.h b/indra/newview/llviewerinput.h
index d18a61eaf0..b7124a54b2 100644
--- a/indra/newview/llviewerinput.h
+++ b/indra/newview/llviewerinput.h
@@ -30,7 +30,6 @@
 #include "llkeyboard.h" // For EKeystate
 #include "llinitparam.h"
 
-const S32 MAX_NAMED_FUNCTIONS = 100;
 const S32 MAX_KEY_BINDINGS = 128; // was 60
 
 class LLNamedFunction
@@ -48,7 +47,6 @@ class LLKeyboardBinding
 public:
     KEY				mKey;
     MASK			mMask;
-    bool			mIgnoreMask; // whether CTRL/ALT/SHIFT should be checked
 
     LLKeyFunc		mFunction;
 };
@@ -58,7 +56,6 @@ class LLMouseBinding
 public:
     EMouseClickType	mMouse;
     MASK			mMask;
-    bool			mIgnoreMask; // whether CTRL/ALT/SHIFT should be checked
 
     LLKeyFunc		mFunction;
 };
@@ -86,8 +83,7 @@ public:
 		Mandatory<std::string>	key,
 								mask,
 								command;
-		Optional<std::string>	mouse; // Note, not mandatory for the sake of backward campatibility
-		Optional<bool>			ignore;
+		Optional<std::string>	mouse; // Note, not mandatory for the sake of backward campatibility with keys.xml
 
 		KeyBinding();
 	};
@@ -131,7 +127,7 @@ public:
     void            scanMouse();
 
 private:
-    bool            scanKey(const LLKeyboardBinding* binding,
+    bool            scanKey(const std::vector<LLKeyboardBinding> &binding,
                             S32 binding_count,
                             KEY key,
                             MASK mask,
@@ -149,34 +145,24 @@ private:
         MOUSE_STATE_SILENT // notified about 'up', do not notify again
     };
     bool			scanMouse(EMouseClickType click, EMouseState state) const;
-    bool            scanMouse(const LLMouseBinding *binding,
+    bool            scanMouse(const std::vector<LLMouseBinding> &binding,
                           S32 binding_count,
                           EMouseClickType mouse,
                           MASK mask,
                           EMouseState state) const;
 
     S32				loadBindingMode(const LLViewerInput::KeyMode& keymode, S32 mode);
-    BOOL			bindKey(const S32 mode, const KEY key, const MASK mask, const bool ignore, const std::string& function_name);
-    BOOL			bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const bool ignore, const std::string& function_name);
+    BOOL			bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name);
+    BOOL			bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const std::string& function_name);
     void			resetBindings();
 
 	// Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here
-    // We process specific keys first, then keys that should ignore mask.
-    // This way with W+ignore defined to 'forward' and with ctrl+W tied to camera,
-    // pressing undefined Shift+W will do 'forward', yet ctrl+W will do 'camera forward'
-    // With A defined to 'turn', shift+A defined to strafe, pressing Shift+W+A will do strafe+forward
 
     // TODO: at some point it is better to remake this, especially keyaboard part
     // would be much better to send to functions actual state of the button than
     // to send what we think function wants based on collection of bools (mKeyRepeated, mKeyLevel, mKeyDown)
-    S32				mKeyBindingCount[MODE_COUNT];
-    S32				mKeyIgnoreMaskCount[MODE_COUNT];
-    S32				mMouseBindingCount[MODE_COUNT];
-    S32				mMouseIgnoreMaskCount[MODE_COUNT];
-    LLKeyboardBinding	mKeyBindings[MODE_COUNT][MAX_KEY_BINDINGS];
-    LLKeyboardBinding	mKeyIgnoreMask[MODE_COUNT][MAX_KEY_BINDINGS];
-    LLMouseBinding		mMouseBindings[MODE_COUNT][MAX_KEY_BINDINGS];
-    LLMouseBinding		mMouseIgnoreMask[MODE_COUNT][MAX_KEY_BINDINGS];
+    std::vector<LLKeyboardBinding>	mKeyBindings[MODE_COUNT];
+    std::vector<LLMouseBinding>		mMouseBindings[MODE_COUNT];
 
 	typedef std::map<U32, U32> key_remap_t;
 	key_remap_t		mRemapKeys[MODE_COUNT];
diff --git a/indra/newview/skins/default/xui/en/control_table_contents.xml b/indra/newview/skins/default/xui/en/control_table_contents.xml
index 00c2d27124..7d4b9be894 100644
--- a/indra/newview/skins/default/xui/en/control_table_contents.xml
+++ b/indra/newview/skins/default/xui/en/control_table_contents.xml
@@ -20,7 +20,7 @@
      enabled="false"
      value="">
         <columns
-         cell_type="icontext"
+         type="icontext"
          column="lst_action"
          font="SansSerif"
          halign="left"
@@ -195,7 +195,7 @@
     <rows
      enabled="false">
         <columns
-         cell_type="icon"
+         type="icon"
          color="0 0 0 0.7"
          halign="center"
          value="menu_separator" />
@@ -204,7 +204,7 @@
      enabled="false"
      value="">
         <columns
-         cell_type="icontext"
+         type="icontext"
          column="lst_action"
          font="SansSerif"
          halign="left"
@@ -417,7 +417,7 @@
     <rows
      enabled="false">
         <columns
-         cell_type="icon"
+         type="icon"
          color="0 0 0 0.7"
          halign="center"
          value="menu_separator" />
@@ -426,7 +426,7 @@
      enabled="false"
      value="">
         <columns
-         cell_type="icontext"
+         type="icontext"
          column="lst_action"
          font="SansSerif"
          halign="left"
@@ -495,7 +495,7 @@
     <rows
      enabled="false">
         <columns
-         cell_type="icon"
+         type="icon"
          color="0 0 0 0.7"
          halign="center"
          value="menu_separator" />
@@ -504,7 +504,7 @@
      enabled="false"
      value="">
         <columns
-         cell_type="icontext"
+         type="icontext"
          column="lst_action"
          font="SansSerif"
          halign="left"
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 32f091938e..255de60d00 100644
--- a/indra/newview/skins/default/xui/en/floater_select_key.xml
+++ b/indra/newview/skins/default/xui/en/floater_select_key.xml
@@ -15,6 +15,15 @@
   <floater.string
    name="mouse">
     Mouse Buttons
+  </floater.string>
+  <floater.string
+   name="basic_description">
+Press a key to set your trigger.
+Allowed input: [INPUT].
+  </floater.string>
+  <floater.string
+   name="reserved_by_menu">
+Combination [KEYSTR] is reserved by menu.
   </floater.string>
     <text
      type="string"
@@ -35,11 +44,11 @@ Allowed input: [INPUT].
      follows="top|left"
      height="20"
      initial_value="false"
-     label="Ignore accelerator keys"
+     label="Ignore extra accelerator keys"
      layout="topleft"
-     left="8"
+     left="28"
      name="ignore_masks"
-     tool_tip="Ignore Shift, Alt and Ctrl keys. Example: This allows to hold W (forward, ignores shift) and Shift+A (slide left) simultaneously and agent will both move forward and slide left."
+     tool_tip="Ignore extra Shift, Alt and Ctrl keys. Example: This allows to hold W (forward, ignores shift) and Shift+A (slide left) simultaneously and agent will both move forward and slide left."
      top_pad="8"
      width="160" />
   
-- 
cgit v1.2.3


From ca56f6d953ad596d4fc02d8568ca542f57aa5119 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Fri, 4 Oct 2019 16:20:07 +0300
Subject: SL-6109 Added default key for voice

---
 indra/newview/app_settings/key_bindings.xml | 12 +++++++++++-
 indra/newview/llkeyconflict.cpp             |  1 +
 indra/newview/llviewerinput.cpp             |  5 +++--
 3 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml
index 0c90ef26df..d0c25f3ed0 100644
--- a/indra/newview/app_settings/key_bindings.xml
+++ b/indra/newview/app_settings/key_bindings.xml
@@ -31,6 +31,8 @@
     <binding key="SPACE" mask="NONE" command="stop_moving"/>
     <binding key="ENTER" mask="NONE" command="start_chat"/>
     <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+    
+    <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
   </first_person>
   <third_person>
     <binding key="A" mask="NONE" command="turn_left"/>
@@ -122,6 +124,8 @@
     <binding key="PAD_DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
     <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/>
     <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>
+
+    <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
   </third_person>
 
   <!-- Basic editing camera control -->
@@ -178,6 +182,8 @@
     <binding key="PAD_PGDN" mask="ALT" command="push_down"/>
     <binding key="PAD_ENTER" mask="ALT" command="start_chat"/>
     <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/>
+
+    <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
   </edit>
   <sitting>
     <binding key="A" mask="ALT" command="spin_around_cw"/>
@@ -273,6 +279,8 @@
 
     <binding key="ENTER" mask="NONE" command="start_chat"/>
     <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+
+    <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
   </sitting>
   <edit_avatar>
     <!--Avatar editing camera controls-->
@@ -298,5 +306,7 @@
     <binding key="PAD_PGDN" mask="NONE" command="edit_avatar_spin_under"/>
     <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
     <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+
+    <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
   </edit_avatar>
-</keys>
\ No newline at end of file
+</keys>
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index 0b9aaea478..71ba0d37b3 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -480,6 +480,7 @@ void LLKeyConflictHandler::saveToSettings()
                     // Still write empty LLKeyData to make sure we will maintain UI position
                     if (data.mKey == KEY_NONE)
                     {
+                        // Might be better idea to be consistent and use NONE. LLViewerInput can work with both cases
                         binding.key = "";
                     }
                     else
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index 95c26cdde2..fda521933f 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -1196,10 +1196,11 @@ S32 LLViewerInput::loadBindingMode(const LLViewerInput::KeyMode& keymode, S32 mo
 		++it)
 	{
         bool processed = false;
-        if (!it->key.getValue().empty())
+        std::string key_str = it->key.getValue();
+        if (!key_str.empty() && key_str != "NONE")
         {
             KEY key;
-            LLKeyboard::keyFromString(it->key, &key);
+            LLKeyboard::keyFromString(key_str, &key);
             if (key != KEY_NONE)
             {
                 MASK mask;
-- 
cgit v1.2.3


From 317dd0e405dfb6ca813118c556f5c23af27cd2a7 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Mon, 28 Oct 2019 17:52:31 +0200
Subject: SL-6109 - Fixed line endings in xml file - Removed obsolete UI
 element and it's code - Fixed issue with return value caused by rebase

---
 indra/newview/llfloaterpreference.cpp              |   35 -
 indra/newview/llfloaterpreference.h                |    1 -
 indra/newview/llviewerinput.cpp                    |    2 +-
 .../default/xui/en/control_table_contents.xml      | 1138 ++++++++++----------
 .../default/xui/en/panel_preferences_sound.xml     |   15 -
 5 files changed, 570 insertions(+), 621 deletions(-)

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 61fd13f219..8328f9914e 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -285,7 +285,6 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
 	mCommitCallbackRegistrar.add("Pref.ResetCache",				boost::bind(&LLFloaterPreference::onClickResetCache, this));
 	mCommitCallbackRegistrar.add("Pref.ClickSkin",				boost::bind(&LLFloaterPreference::onClickSkin, this,_1, _2));
 	mCommitCallbackRegistrar.add("Pref.SelectSkin",				boost::bind(&LLFloaterPreference::onSelectSkin, this));
-	mCommitCallbackRegistrar.add("Pref.VoiceSetMiddleMouse",	boost::bind(&LLFloaterPreference::onClickSetMiddleMouse, this));
 	mCommitCallbackRegistrar.add("Pref.SetSounds",				boost::bind(&LLFloaterPreference::onClickSetSounds, this));
 	mCommitCallbackRegistrar.add("Pref.ClickEnablePopup",		boost::bind(&LLFloaterPreference::onClickEnablePopup, this));
 	mCommitCallbackRegistrar.add("Pref.ClickDisablePopup",		boost::bind(&LLFloaterPreference::onClickDisablePopup, this));	
@@ -1571,21 +1570,6 @@ void LLFloaterPreference::onChangeQuality(const LLSD& data)
 	refresh();
 }
 
-void LLFloaterPreference::onClickSetMiddleMouse()
-{
-	LLUICtrl* p2t_line_editor = getChild<LLUICtrl>("modifier_combo");
-
-	// update the control right away since we no longer wait for apply
-	p2t_line_editor->setControlValue(MIDDLE_MOUSE_CV);
-
-	//push2talk button "middle mouse" control value is in English, need to localize it for presentation
-	LLPanel* advanced_preferences = dynamic_cast<LLPanel*>(p2t_line_editor->getParent());
-	if (advanced_preferences)
-	{
-		p2t_line_editor->setValue(advanced_preferences->getString("middle_mouse"));
-	}
-}
-
 void LLFloaterPreference::onClickSetSounds()
 {
 	// Disable Enable gesture sounds checkbox if the master sound is disabled 
@@ -2272,25 +2256,6 @@ BOOL LLPanelPreference::postBuild()
 		getChild<LLTextBox>("mute_chb_label")->setClickedCallback(boost::bind(&toggleMuteWhenMinimized));
 	}
 
-	//////////////////////PanelAdvanced ///////////////////
-	if (hasChild("modifier_combo", TRUE))
-	{
-		//localizing if push2talk button is set to middle mouse
-		std::string modifier_value = getChild<LLUICtrl>("modifier_combo")->getValue().asString();
-		if (MIDDLE_MOUSE_CV == modifier_value)
-		{
-			getChild<LLUICtrl>("modifier_combo")->setValue(getString("middle_mouse"));
-		}
-		else if (MOUSE_BUTTON_4_CV == modifier_value)
-		{
-			getChild<LLUICtrl>("modifier_combo")->setValue(getString("button4_mouse"));
-		}
-		else if (MOUSE_BUTTON_5_CV == modifier_value)
-		{
-			getChild<LLUICtrl>("modifier_combo")->setValue(getString("button5_mouse"));
-		}
-	}
-
 	//////////////////////PanelSetup ///////////////////
 	if (hasChild("max_bandwidth"), TRUE)
 	{
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index bc19564bf6..f08f2aa2ba 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -143,7 +143,6 @@ public:
 	void onClickResetCache();
 	void onClickSkin(LLUICtrl* ctrl,const LLSD& userdata);
 	void onSelectSkin();
-	void onClickSetMiddleMouse();
 	void onClickSetSounds();
 	void onClickEnablePopup();
 	void onClickDisablePopup();	
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index fda521933f..8df66b4ce9 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -1309,7 +1309,7 @@ bool LLViewerInput::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
 {
 	if (LLApp::isExiting())
 	{
-		return;
+		return false;
 	}
 
 	S32 mode = getMode();
diff --git a/indra/newview/skins/default/xui/en/control_table_contents.xml b/indra/newview/skins/default/xui/en/control_table_contents.xml
index 7d4b9be894..f078e80dff 100644
--- a/indra/newview/skins/default/xui/en/control_table_contents.xml
+++ b/indra/newview/skins/default/xui/en/control_table_contents.xml
@@ -1,569 +1,569 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<contents>
-    <columns
-     relative_width="0.34"
-     label="Action"
-     name="lst_action" />
-    <columns
-     relative_width="0.22"
-     label="Prymary Control"
-     name="lst_ctrl1" />
-    <columns
-     relative_width="0.22"
-     label="Alternate 1"
-     name="lst_ctrl2" />
-    <columns
-     relative_width="0.22"
-     label="Alternate 2"
-     name="lst_ctrl3" />
-    <rows
-     enabled="false"
-     value="">
-        <columns
-         type="icontext"
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         label="Move Actions"
-         name="lst_action"
-         value="Move_Walk_Off" />
-    </rows>
-    <rows
-     value="walk_to">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Walk to location mouse cursor points to"
-         value="Walk to" />
-    </rows>
-    <rows
-     value="teleport_to">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Teleport to location mouse cursor points to, but not all locations allow direct teleportation so you might be teleported closer to destination instead"
-         value="Teleport to" />
-    </rows>
-    <rows
-     value="push_forward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Move Forward" />
-    </rows>
-    <rows
-     value="push_backward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Move Backward" />
-    </rows>
-    <rows
-     value="turn_left">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Left" />
-    </rows>
-    <rows
-     value="turn_right">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Right" />
-    </rows>
-    <rows
-     value="slide_left">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Strafe left" />
-    </rows>
-    <rows
-     value="slide_right">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Strafe right" />
-    </rows>
-    <rows
-     value="jump">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Jump/Up" />
-    </rows>
-    <rows
-     value="push_down">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Down" />
-    </rows>
-    <rows
-     value="run_forward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Run Forward" />
-    </rows>
-    <rows
-     value="run_backward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Run Backward" />
-    </rows>
-    <rows
-     value="run_left">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Run Left" />
-    </rows>
-    <rows
-     value="run_right">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Run Right" />
-    </rows>
-    <rows
-     value="toggle_run">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Toggle Run" />
-    </rows>
-    <rows
-     value="toggle_fly">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Fly/Stop flying" />
-    </rows>
-    <rows
-     value="toggle_sit">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Sit/Stand" />
-    </rows>
-    <rows
-     value="stop_moving">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Stop Moving" />
-    </rows>
-    <rows
-     enabled="false">
-        <columns
-         type="icon"
-         color="0 0 0 0.7"
-         halign="center"
-         value="menu_separator" />
-    </rows>
-    <rows
-     enabled="false"
-     value="">
-        <columns
-         type="icontext"
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         label="Camera"
-         name="lst_action"
-         value="Cam_FreeCam_Off" />
-    </rows>
-    <rows
-     value="look_up">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Look Up" />
-    </rows>
-    <rows
-     value="look_down">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Look Down" />
-    </rows>
-    <rows
-     value="move_forward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Forward" />
-    </rows>
-    <rows
-     value="move_backward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Backward" />
-    </rows>
-    <rows
-     value="move_forward_fast">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Forward Fast" />
-    </rows>
-    <rows
-     value="move_backward_fast">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Backward Fast" />
-    </rows>
-    <rows
-     value="move_forward_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Forward Sitting" />
-    </rows>
-    <rows
-     value="move_backward_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Backward Sitting" />
-    </rows>
-    <rows
-     value="spin_over">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Spin Over" />
-    </rows>
-    <rows
-     value="spin_under">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Spin Under" />
-    </rows>
-    <rows
-     value="spin_over_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Spin Over" />
-    </rows>
-    <rows
-     value="spin_under_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Spin Under" />
-    </rows>
-    <rows
-     value="pan_up">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan Up" />
-    </rows>
-    <rows
-     value="pan_down">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan Down" />
-    </rows>
-    <rows
-     value="pan_left">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan Left" />
-    </rows>
-    <rows
-     value="pan_right">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan Right" />
-    </rows>
-    <rows
-     value="pan_in">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan In" />
-    </rows>
-    <rows
-     value="pan_out">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan Out" />
-    </rows>
-    <rows
-     value="spin_around_ccw">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around counterclockwise"
-         value="Counterclockwise" />
-    </rows>
-    <rows
-     value="spin_around_cw">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around clockwise"
-         value="Clockwise" />
-    </rows>
-    <rows
-     value="spin_around_ccw_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around counterclockwise sitting"
-         value="Counterclockwise Sitting" />
-    </rows>
-    <rows
-     value="spin_around_cw_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around clockwise sitting"
-         value="Clockwise Sitting" />
-    </rows>
-    <rows
-     enabled="false">
-        <columns
-         type="icon"
-         color="0 0 0 0.7"
-         halign="center"
-         value="menu_separator" />
-    </rows>
-    <rows
-     enabled="false"
-     value="">
-        <columns
-         type="icontext"
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         label="Editing"
-         name="lst_action"
-         value="Tool_Dozer" />
-    </rows>
-    <rows
-     value="edit_avatar_spin_ccw">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around avatar counterclockwise"
-         value="Counterclockwise" />
-    </rows>
-    <rows
-     value="edit_avatar_spin_cw">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around avatar clockwise"
-         value="Clockwise" />
-    </rows>
-    <rows
-     value="edit_avatar_spin_over">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin over avatar"
-         value="Camera Spin Over" />
-    </rows>
-    <rows
-     value="edit_avatar_spin_under">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin under avatar"
-         value="Camera Spin Under" />
-    </rows>
-    <rows
-     value="edit_avatar_move_forward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Forward" />
-    </rows>
-    <rows
-     value="edit_avatar_move_backward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Backward" />
-    </rows>
-    <rows
-     enabled="false">
-        <columns
-         type="icon"
-         color="0 0 0 0.7"
-         halign="center"
-         value="menu_separator" />
-    </rows>
-    <rows
-     enabled="false"
-     value="">
-        <columns
-         type="icontext"
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         label="Sound and Media"
-         name="lst_action"
-         value="Audio_Press" />
-    </rows>
-    <rows
-     value="toggle_pause_media">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Play/Pause Media" />
-    </rows>
-    <rows
-     value="toggle_enable_media">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Play/Stop All Media" />
-    </rows>
-    <rows
-     value="voice_follow_key">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Voice" />
-    </rows>
-    <rows
-     value="toggle_voice">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Toggle Voice" />
-    </rows>
-    <rows
-     value="start_chat">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Start Chat" />
-    </rows>
-    <rows
-     value="start_gesture">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Start Gesture" />
-    </rows>
-</contents>
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<contents>
+    <columns
+     relative_width="0.34"
+     label="Action"
+     name="lst_action" />
+    <columns
+     relative_width="0.22"
+     label="Prymary Control"
+     name="lst_ctrl1" />
+    <columns
+     relative_width="0.22"
+     label="Alternate 1"
+     name="lst_ctrl2" />
+    <columns
+     relative_width="0.22"
+     label="Alternate 2"
+     name="lst_ctrl3" />
+    <rows
+     enabled="false"
+     value="">
+        <columns
+         type="icontext"
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         label="Move Actions"
+         name="lst_action"
+         value="Move_Walk_Off" />
+    </rows>
+    <rows
+     value="walk_to">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Walk to location mouse cursor points to"
+         value="Walk to" />
+    </rows>
+    <rows
+     value="teleport_to">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Teleport to location mouse cursor points to, but not all locations allow direct teleportation so you might be teleported closer to destination instead"
+         value="Teleport to" />
+    </rows>
+    <rows
+     value="push_forward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Move Forward" />
+    </rows>
+    <rows
+     value="push_backward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Move Backward" />
+    </rows>
+    <rows
+     value="turn_left">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Left" />
+    </rows>
+    <rows
+     value="turn_right">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Right" />
+    </rows>
+    <rows
+     value="slide_left">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Strafe left" />
+    </rows>
+    <rows
+     value="slide_right">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Strafe right" />
+    </rows>
+    <rows
+     value="jump">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Jump/Up" />
+    </rows>
+    <rows
+     value="push_down">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Down" />
+    </rows>
+    <rows
+     value="run_forward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Run Forward" />
+    </rows>
+    <rows
+     value="run_backward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Run Backward" />
+    </rows>
+    <rows
+     value="run_left">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Run Left" />
+    </rows>
+    <rows
+     value="run_right">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Run Right" />
+    </rows>
+    <rows
+     value="toggle_run">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Toggle Run" />
+    </rows>
+    <rows
+     value="toggle_fly">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Fly/Stop flying" />
+    </rows>
+    <rows
+     value="toggle_sit">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Sit/Stand" />
+    </rows>
+    <rows
+     value="stop_moving">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Stop Moving" />
+    </rows>
+    <rows
+     enabled="false">
+        <columns
+         type="icon"
+         color="0 0 0 0.7"
+         halign="center"
+         value="menu_separator" />
+    </rows>
+    <rows
+     enabled="false"
+     value="">
+        <columns
+         type="icontext"
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         label="Camera"
+         name="lst_action"
+         value="Cam_FreeCam_Off" />
+    </rows>
+    <rows
+     value="look_up">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Look Up" />
+    </rows>
+    <rows
+     value="look_down">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Look Down" />
+    </rows>
+    <rows
+     value="move_forward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Forward" />
+    </rows>
+    <rows
+     value="move_backward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Backward" />
+    </rows>
+    <rows
+     value="move_forward_fast">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Forward Fast" />
+    </rows>
+    <rows
+     value="move_backward_fast">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Backward Fast" />
+    </rows>
+    <rows
+     value="move_forward_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Forward Sitting" />
+    </rows>
+    <rows
+     value="move_backward_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Backward Sitting" />
+    </rows>
+    <rows
+     value="spin_over">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Spin Over" />
+    </rows>
+    <rows
+     value="spin_under">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Spin Under" />
+    </rows>
+    <rows
+     value="spin_over_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Spin Over" />
+    </rows>
+    <rows
+     value="spin_under_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Spin Under" />
+    </rows>
+    <rows
+     value="pan_up">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan Up" />
+    </rows>
+    <rows
+     value="pan_down">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan Down" />
+    </rows>
+    <rows
+     value="pan_left">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan Left" />
+    </rows>
+    <rows
+     value="pan_right">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan Right" />
+    </rows>
+    <rows
+     value="pan_in">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan In" />
+    </rows>
+    <rows
+     value="pan_out">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan Out" />
+    </rows>
+    <rows
+     value="spin_around_ccw">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around counterclockwise"
+         value="Counterclockwise" />
+    </rows>
+    <rows
+     value="spin_around_cw">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around clockwise"
+         value="Clockwise" />
+    </rows>
+    <rows
+     value="spin_around_ccw_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around counterclockwise sitting"
+         value="Counterclockwise Sitting" />
+    </rows>
+    <rows
+     value="spin_around_cw_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around clockwise sitting"
+         value="Clockwise Sitting" />
+    </rows>
+    <rows
+     enabled="false">
+        <columns
+         type="icon"
+         color="0 0 0 0.7"
+         halign="center"
+         value="menu_separator" />
+    </rows>
+    <rows
+     enabled="false"
+     value="">
+        <columns
+         type="icontext"
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         label="Editing"
+         name="lst_action"
+         value="Tool_Dozer" />
+    </rows>
+    <rows
+     value="edit_avatar_spin_ccw">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around avatar counterclockwise"
+         value="Counterclockwise" />
+    </rows>
+    <rows
+     value="edit_avatar_spin_cw">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around avatar clockwise"
+         value="Clockwise" />
+    </rows>
+    <rows
+     value="edit_avatar_spin_over">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin over avatar"
+         value="Camera Spin Over" />
+    </rows>
+    <rows
+     value="edit_avatar_spin_under">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin under avatar"
+         value="Camera Spin Under" />
+    </rows>
+    <rows
+     value="edit_avatar_move_forward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Forward" />
+    </rows>
+    <rows
+     value="edit_avatar_move_backward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Backward" />
+    </rows>
+    <rows
+     enabled="false">
+        <columns
+         type="icon"
+         color="0 0 0 0.7"
+         halign="center"
+         value="menu_separator" />
+    </rows>
+    <rows
+     enabled="false"
+     value="">
+        <columns
+         type="icontext"
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         label="Sound and Media"
+         name="lst_action"
+         value="Audio_Press" />
+    </rows>
+    <rows
+     value="toggle_pause_media">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Play/Pause Media" />
+    </rows>
+    <rows
+     value="toggle_enable_media">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Play/Stop All Media" />
+    </rows>
+    <rows
+     value="voice_follow_key">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Voice" />
+    </rows>
+    <rows
+     value="toggle_voice">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Toggle Voice" />
+    </rows>
+    <rows
+     value="start_chat">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Start Chat" />
+    </rows>
+    <rows
+     value="start_gesture">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Start Gesture" />
+    </rows>
+</contents>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
index 6b54438b05..c2995393fd 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
@@ -470,21 +470,6 @@
   width="237"
   tool_tip="When in toggle mode, press and release the trigger key ONCE to switch your microphone on or off. When not in toggle mode, the microphone broadcasts your voice only while the trigger is being held down."
   top_pad="3"/>
-  <button
-     enabled_control="EnableVoiceChat"
-     follows="top|left"
-     halign="center"
-     height="23"
-     image_overlay="Refresh_Off"
-     layout="topleft"
-     tool_tip="Reset to Middle Mouse Button"
-     mouse_opaque="true"
-     name="set_voice_middlemouse_button"
-     left_pad="5"
-     width="25">
-    <button.commit_callback
-    function="Pref.VoiceSetMiddleMouse" />
-  </button>
   <button
    control_name="ShowDeviceSettings"
    follows="left|top"
-- 
cgit v1.2.3


From 8ccf79735ec399cc6b88f25cd2ceafac6858ecd2 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Mon, 28 Oct 2019 18:27:13 +0200
Subject: SL-6109 Fixed conflict resolution issue caused by menu accelerators

---
 indra/llui/llmenugl.cpp              | 53 ++++++++++++++++++++++--------------
 indra/llui/llmenugl.h                |  7 +++--
 indra/newview/llkeyconflict.cpp      | 12 ++++++--
 indra/newview/llsetkeybinddialog.cpp | 53 ++++++++++++++++++++++++++++--------
 indra/newview/llsetkeybinddialog.h   |  9 +++++-
 indra/newview/llviewerwindow.cpp     |  9 ++++++
 6 files changed, 104 insertions(+), 39 deletions(-)

diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 986f3362b7..5c8c30e6ac 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -212,6 +212,12 @@ LLSD LLMenuItemGL::getValue() const
 	return getLabel();
 }
 
+//virtual
+bool LLMenuItemGL::hasAccelerator(const KEY &key, const MASK &mask) const
+{
+	return (mAcceleratorKey == key) && (mAcceleratorMask == mask);
+}
+
 //virtual
 BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask)
 {
@@ -1017,6 +1023,11 @@ BOOL LLMenuItemBranchGL::handleMouseUp(S32 x, S32 y, MASK mask)
 	return TRUE;
 }
 
+bool LLMenuItemBranchGL::hasAccelerator(const KEY &key, const MASK &mask) const
+{
+	return getBranch() && getBranch()->hasAccelerator(key, mask);
+}
+
 BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask)
 {
 	return getBranch() && getBranch()->handleAcceleratorKey(key, mask);
@@ -3001,6 +3012,27 @@ void LLMenuGL::updateParent(LLView* parentp)
 	}
 }
 
+bool LLMenuGL::hasAccelerator(const KEY &key, const MASK &mask) const
+{
+	if (key == KEY_NONE)
+	{
+		return false;
+	}
+	// Note: checking this way because mAccelerators seems to be broken
+	// mAccelerators probably needs to be cleaned up or fixed
+	// It was used for dupplicate accelerator avoidance.
+	item_list_t::const_iterator item_iter;
+	for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
+	{
+		LLMenuItemGL* itemp = *item_iter;
+		if (itemp->hasAccelerator(key, mask))
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
 BOOL LLMenuGL::handleAcceleratorKey(KEY key, MASK mask)
 {
 	// don't handle if not enabled
@@ -3514,27 +3546,6 @@ S32 LLMenuBarGL::getRightmostMenuEdge()
 	return (*item_iter)->getRect().mRight;
 }
 
-bool LLMenuBarGL::hasAccelerator(const KEY &key, const MASK &mask) const
-{
-    if (key == KEY_NONE)
-    {
-        return false;
-    }
-
-    LLMenuKeyboardBinding *accelerator = NULL;
-    std::list<LLMenuKeyboardBinding*>::const_iterator list_it;
-    for (list_it = mAccelerators.begin(); list_it != mAccelerators.end(); ++list_it)
-    {
-        accelerator = *list_it;
-        if ((accelerator->mKey == key) && (accelerator->mMask == (mask & MASK_NORMALKEYS)))
-        {
-            return true;
-        }
-    }
-
-    return false;
-}
-
 // add a vertical separator to this menu
 BOOL LLMenuBarGL::addSeparator()
 {
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 0653864892..f3844af507 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -98,6 +98,7 @@ public:
 	/*virtual*/ void setValue(const LLSD& value);
 	/*virtual*/ LLSD getValue() const;
 
+	virtual bool hasAccelerator(const KEY &key, const MASK &mask) const;
 	virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
 
 	LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); }
@@ -443,7 +444,8 @@ public:
 	/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
 	/*virtual*/ void removeChild( LLView* ctrl);
 	/*virtual*/ BOOL postBuild();
-
+	
+	virtual bool hasAccelerator(const KEY &key, const MASK &mask) const;
 	virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
 
 	LLMenuGL* findChildMenuByName(const std::string& name, BOOL recurse) const;
@@ -632,6 +634,7 @@ public:
 	
 	virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
 
+	virtual bool hasAccelerator(const KEY &key, const MASK &mask) const;
 	virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
 
 	// check if we've used these accelerators already
@@ -792,8 +795,6 @@ public:
 
 	void resetMenuTrigger() { mAltKeyTrigger = FALSE; }
 
-	bool hasAccelerator(const KEY &key, const MASK &mask) const;
-
 private:
 	// add a menu - this will create a drop down menu.
 	virtual BOOL appendMenu( LLMenuGL* menu );
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index 71ba0d37b3..fcf1a7953c 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -174,17 +174,23 @@ bool LLKeyConflictHandler::canAssignControl(const std::string &control_name)
 // static
 bool LLKeyConflictHandler::isReservedByMenu(const KEY &key, const MASK &mask)
 {
-    return gMenuBarView->hasAccelerator(key, mask) || gLoginMenuBarView->hasAccelerator(key, mask);
+    if (key == KEY_NONE)
+    {
+        return false;
+    }
+    return (gMenuBarView && gMenuBarView->hasAccelerator(key, mask))
+           || (gLoginMenuBarView && gLoginMenuBarView->hasAccelerator(key, mask));
 }
 
 // static
 bool LLKeyConflictHandler::isReservedByMenu(const LLKeyData &data)
 {
-    if (data.mMouse != CLICK_NONE)
+    if (data.mMouse != CLICK_NONE || data.mKey == KEY_NONE)
     {
         return false;
     }
-    return gMenuBarView->hasAccelerator(data.mKey, data.mMask) || gLoginMenuBarView->hasAccelerator(data.mKey, data.mMask);
+    return (gMenuBarView && gMenuBarView->hasAccelerator(data.mKey, data.mMask))
+           || (gLoginMenuBarView && gLoginMenuBarView->hasAccelerator(data.mKey, data.mMask));
 }
 
 bool LLKeyConflictHandler::registerControl(const std::string &control_name, U32 index, EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask)
diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp
index 320f1f297d..806c70aa03 100644
--- a/indra/newview/llsetkeybinddialog.cpp
+++ b/indra/newview/llsetkeybinddialog.cpp
@@ -28,11 +28,10 @@
 
 #include "llsetkeybinddialog.h"
 
-//#include "llkeyboard.h"
-
 #include "llbutton.h"
 #include "llcheckboxctrl.h"
 #include "lleventtimer.h"
+#include "llfloaterreg.h"
 #include "llfocusmgr.h"
 #include "llkeyconflict.h"
 
@@ -65,6 +64,8 @@ private:
     callback_t mCallback;
 };
 
+bool LLSetKeyBindDialog::sRecordKeys = false;
+
 LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key)
     : LLModalDialog(key),
     pParent(NULL),
@@ -93,9 +94,17 @@ BOOL LLSetKeyBindDialog::postBuild()
     return TRUE;
 }
 
+//virtual
+void LLSetKeyBindDialog::onOpen(const LLSD& data)
+{
+     sRecordKeys = true;
+     LLModalDialog::onOpen(data);
+}
+
 //virtual
 void LLSetKeyBindDialog::onClose(bool app_quiting)
 {
+    sRecordKeys = false;
     if (pParent)
     {
         pParent->onCancelKeyBind();
@@ -145,20 +154,41 @@ void LLSetKeyBindDialog::setParent(LLKeyBindResponderInterface* parent, LLView*
     pCheckBox->setValue(false);
 }
 
-BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
+// static
+bool LLSetKeyBindDialog::recordKey(KEY key, MASK mask)
+{
+    if (sRecordKeys)
+    {
+        LLSetKeyBindDialog* dialog = LLFloaterReg::getTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD());
+        if (dialog && dialog->getVisible())
+        {
+            return dialog->recordAndHandleKey(key, mask);
+        }
+        else
+        {
+            LL_WARNS() << "Key recording was set despite no open dialog" << LL_ENDL;
+            sRecordKeys = false;
+        }
+    }
+    return false;
+}
+
+bool LLSetKeyBindDialog::recordAndHandleKey(KEY key, MASK mask)
 {
     if ((key == 'Q' && mask == MASK_CONTROL)
         || key == KEY_ESCAPE)
     {
+        sRecordKeys = false;
         closeFloater();
-        return TRUE;
+        return true;
     }
 
     if (key == KEY_DELETE)
     {
         setKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
+        sRecordKeys = false;
         closeFloater();
-        return FALSE;
+        return false;
     }
 
     // forbidden keys
@@ -166,36 +196,37 @@ BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
         || key == KEY_RETURN
         || key == KEY_BACKSPACE)
     {
-        return FALSE;
+        return false;
     }
 
     if ((mKeyFilterMask & ALLOW_MASKS) == 0
         && (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT))
     {
         // mask by themself are not allowed
-        return FALSE;
+        return false;
     }
     else if ((mKeyFilterMask & ALLOW_KEYS) == 0)
     {
         // basic keys not allowed
-        return FALSE;
+        return false;
     }
     else if ((mKeyFilterMask & ALLOW_MASK_KEYS) == 0 && mask != 0)
     {
         // masked keys not allowed
-        return FALSE;
+        return false;
     }
 
     if (LLKeyConflictHandler::isReservedByMenu(key, mask))
     {
         pDesription->setText(getString("reserved_by_menu"));
         pDesription->setTextArg("[KEYSTR]", LLKeyboard::stringFromAccelerator(mask,key));
-        return TRUE;
+        return true;
     }
 
     setKeyBind(CLICK_NONE, key, mask, pCheckBox->getValue().asBoolean());
+    sRecordKeys = false;
     closeFloater();
-    return TRUE;
+    return true;
 }
 
 BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down)
diff --git a/indra/newview/llsetkeybinddialog.h b/indra/newview/llsetkeybinddialog.h
index 8faa2cc363..16a2d768e4 100644
--- a/indra/newview/llsetkeybinddialog.h
+++ b/indra/newview/llsetkeybinddialog.h
@@ -62,12 +62,16 @@ public:
     ~LLSetKeyBindDialog();
 
     /*virtual*/ BOOL postBuild();
+    /*virtual*/ void onOpen(const LLSD& data);
     /*virtual*/ void onClose(bool app_quiting);
     /*virtual*/ void draw();
 
     void setParent(LLKeyBindResponderInterface* parent, LLView* frustum_origin, U32 key_mask = DEFAULT_KEY_FILTER);
 
-    BOOL handleKeyHere(KEY key, MASK mask);
+    // Wrapper around recordAndHandleKey
+    // It does not record, it handles, but handleKey function is already in use
+    static bool recordKey(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);
@@ -77,6 +81,7 @@ public:
     class Updater;
 
 private:
+    bool recordAndHandleKey(KEY key, MASK mask);
     void setKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore);
     LLKeyBindResponderInterface *pParent;
     LLCheckBoxCtrl *pCheckBox;
@@ -84,6 +89,8 @@ private:
 
     U32 mKeyFilterMask;
     Updater *pUpdater;
+
+    static bool sRecordKeys; // for convinience and not to check instance each time
 };
 
 
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 3c2ec369ec..c2a89819a6 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -45,6 +45,7 @@
 #include "llmeshrepository.h"
 #include "llnotificationhandler.h"
 #include "llpanellogin.h"
+#include "llsetkeybinddialog.h"
 #include "llviewerinput.h"
 #include "llviewermenu.h"
 
@@ -2716,6 +2717,14 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
 	// hide tooltips on keypress
 	LLToolTipMgr::instance().blockToolTips();
 
+    // let menus handle navigation keys for navigation
+    if (LLSetKeyBindDialog::recordKey(key, mask))
+    {
+        LL_DEBUGS() << "Key handled by LLSetKeyBindDialog" << LL_ENDL;
+        LLViewerEventRecorder::instance().logKeyEvent(key,mask);
+        return TRUE;
+    }
+
     LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
 
     if (keyboard_focus
-- 
cgit v1.2.3


From eb54fccff7bb6e6c8eacdb460b4647f70bd9bffd Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Mon, 28 Oct 2019 19:34:40 +0200
Subject: SL-6109 Better running

---
 indra/newview/llviewerinput.cpp | 68 +++++++++++++++++++++++++++++------------
 1 file changed, 48 insertions(+), 20 deletions(-)

diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index 8df66b4ce9..50618350be 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -650,15 +650,22 @@ bool start_gesture( EKeystate s )
 
 bool run_forward(EKeystate s)
 {
-    if (KEYSTATE_DOWN == s)
+    if (KEYSTATE_UP != s)
     {
-        gAgent.setAlwaysRun();
-        gAgent.setRunning();
-        gAgent.sendWalkRun(true);
+        if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD)
+        {
+            gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_FORWARD;
+        }
+        if (!gAgent.getRunning())
+        {
+            gAgent.setRunning();
+            gAgent.sendWalkRun(true);
+        }
     }
     else if(KEYSTATE_UP == s)
     {
-        gAgent.clearAlwaysRun();
+        if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_FORWARD)
+            gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE;
         gAgent.clearRunning();
         gAgent.sendWalkRun(false);
     }
@@ -668,15 +675,22 @@ bool run_forward(EKeystate s)
 
 bool run_backward(EKeystate s)
 {
-    if (KEYSTATE_DOWN == s)
+    if (KEYSTATE_UP != s)
     {
-        gAgent.setAlwaysRun();
-        gAgent.setRunning();
-        gAgent.sendWalkRun(true);
+        if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD)
+        {
+            gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_BACKWARD;
+        }
+        if (!gAgent.getRunning())
+        {
+            gAgent.setRunning();
+            gAgent.sendWalkRun(true);
+        }
     }
     else if (KEYSTATE_UP == s)
     {
-        gAgent.clearAlwaysRun();
+        if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_BACKWARD)
+            gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE;
         gAgent.clearRunning();
         gAgent.sendWalkRun(false);
     }
@@ -686,15 +700,22 @@ bool run_backward(EKeystate s)
 
 bool run_left(EKeystate s)
 {
-    if (KEYSTATE_DOWN == s)
+    if (KEYSTATE_UP != s)
     {
-        gAgent.setAlwaysRun();
-        gAgent.setRunning();
-        gAgent.sendWalkRun(true);
+        if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT)
+        {
+            gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_SLIDELEFT;
+        }
+        if (!gAgent.getRunning())
+        {
+            gAgent.setRunning();
+            gAgent.sendWalkRun(true);
+        }
     }
     else if (KEYSTATE_UP == s)
     {
-        gAgent.clearAlwaysRun();
+        if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_SLIDELEFT)
+            gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE;
         gAgent.clearRunning();
         gAgent.sendWalkRun(false);
     }
@@ -704,15 +725,22 @@ bool run_left(EKeystate s)
 
 bool run_right(EKeystate s)
 {
-    if (KEYSTATE_DOWN == s)
+    if (KEYSTATE_UP != s)
     {
-        gAgent.setAlwaysRun();
-        gAgent.setRunning();
-        gAgent.sendWalkRun(true);
+        if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT)
+        {
+            gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_SLIDERIGHT;
+            if (!gAgent.getRunning())
+            {
+                gAgent.setRunning();
+                gAgent.sendWalkRun(true);
+            }
+        }
     }
     else if (KEYSTATE_UP == s)
     {
-        gAgent.clearAlwaysRun();
+        if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_SLIDERIGHT)
+            gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE;
         gAgent.clearRunning();
         gAgent.sendWalkRun(false);
     }
-- 
cgit v1.2.3


From 8e734f543beb4bbfd4fb213e53d7fa8bc4302848 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Wed, 30 Oct 2019 20:48:54 +0200
Subject: SL-6109 Now changes are applied on the go and reverted on cancel

---
 indra/newview/llfloaterpreference.cpp |   6 ++
 indra/newview/llkeyconflict.cpp       | 117 ++++++++++++++++++++++++++++------
 indra/newview/llkeyconflict.h         |  18 +++++-
 3 files changed, 122 insertions(+), 19 deletions(-)

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 8328f9914e..9305f38a29 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2916,6 +2916,8 @@ void LLPanelPreferenceControls::onRestoreDefaults()
     for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
     {
         mConflictHandler[mEditingMode].resetToDefaults();
+        // Apply changes to viewer as 'temporary'
+        mConflictHandler[mEditingMode].saveToSettings(true);
     }
 }
 
@@ -2930,6 +2932,8 @@ bool LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MAS
     if ( mEditingColumn > 0)
     {
         mConflictHandler[mEditingMode].registerControl(mEditingControl, mEditingColumn - 1, click, key, mask, true);
+        // Apply changes to viewer as 'temporary'
+        mConflictHandler[mEditingMode].saveToSettings(true);
     }
 
     updateTable();
@@ -2946,6 +2950,8 @@ void LLPanelPreferenceControls::onDefaultKeyBind()
     if (mEditingColumn > 0)
     {
         mConflictHandler[mEditingMode].resetToDefault(mEditingControl, mEditingColumn - 1);
+        // Apply changes to viewer as 'temporary'
+        mConflictHandler[mEditingMode].saveToSettings(true);
     }
     updateTable();
 }
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index fcf1a7953c..d88038816b 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -40,10 +40,11 @@
 #include "llviewerinput.h"
 #include "llviewermenu.h"
 #include "llxuiparser.h"
-//#include "llstring.h"
 
-static const std::string saved_settings_key_controls[] = { "placeholder" };
+static const std::string saved_settings_key_controls[] = { "placeholder" }; // add settings from gSavedSettings here
 
+static const std::string filename_default = "key_bindings.xml";
+static const std::string filename_temporary = "key_bindings_tmp.xml"; // used to apply uncommited changes on the go.
 
 // LLKeyboard::stringFromMask is meant for UI and is OS dependent,
 // so this class uses it's own version
@@ -128,18 +129,28 @@ EMouseClickType mouse_from_string(const std::string& input)
 
 // LLKeyConflictHandler
 
+S32 LLKeyConflictHandler::sTemporaryFileUseCount = 0;
+
 LLKeyConflictHandler::LLKeyConflictHandler()
-    : mHasUnsavedChanges(false)
+:   mHasUnsavedChanges(false),
+    mUsesTemporaryFile(false),
+    mLoadMode(MODE_COUNT)
 {
 }
 
 LLKeyConflictHandler::LLKeyConflictHandler(ESourceMode mode)
-    : mHasUnsavedChanges(false),
+:   mHasUnsavedChanges(false),
+    mUsesTemporaryFile(false),
     mLoadMode(mode)
 {
     loadFromSettings(mode);
 }
 
+LLKeyConflictHandler::~LLKeyConflictHandler()
+{
+    clearUnsavedChanges();
+}
+
 bool LLKeyConflictHandler::canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask)
 {
     return mControlsMap[control_name].canHandle(mouse_ind, key, mask);
@@ -355,6 +366,7 @@ bool LLKeyConflictHandler::loadFromSettings(const ESourceMode &load_mode, const
             }
             break;
         default:
+            LL_ERRS() << "Not implememted mode " << load_mode << LL_ENDL;
             break;
         }
     }
@@ -381,7 +393,7 @@ void LLKeyConflictHandler::loadFromSettings(ESourceMode load_mode)
     else
     {
         // load defaults
-        std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "key_bindings.xml");
+        std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, filename_default);
         if (!loadFromSettings(load_mode, filename, &mDefaultsMap))
         {
             LL_WARNS() << "Failed to load default settings, aborting" << LL_ENDL;
@@ -389,7 +401,7 @@ void LLKeyConflictHandler::loadFromSettings(ESourceMode load_mode)
         }
 
         // load user's
-        filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml");
+        filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default);
         if (!gDirUtilp->fileExists(filename) || loadFromSettings(load_mode, filename, &mControlsMap))
         {
             // mind placeholders
@@ -399,7 +411,7 @@ void LLKeyConflictHandler::loadFromSettings(ESourceMode load_mode)
     mLoadMode = load_mode;
 }
 
-void LLKeyConflictHandler::saveToSettings()
+void LLKeyConflictHandler::saveToSettings(bool temporary)
 {
     if (mControlsMap.empty())
     {
@@ -408,6 +420,8 @@ void LLKeyConflictHandler::saveToSettings()
 
     if (mLoadMode == MODE_SAVED_SETTINGS)
     {
+        // Does not support 'temporary', preferences handle that themself
+        // so in case of saved settings we just do not clear mHasUnsavedChanges
         control_map_t::iterator iter = mControlsMap.begin();
         control_map_t::iterator end = mControlsMap.end();
 
@@ -440,10 +454,24 @@ void LLKeyConflictHandler::saveToSettings()
     }
     else
     {
-        // loaded full copy of original file
-        std::string filename = gDirUtilp->findFile("key_bindings.xml",
-            gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
-            gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
+        // Determine what file to load and load full copy of that file
+        std::string filename;
+
+        if (temporary)
+        {
+            filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_temporary);
+            if (!gDirUtilp->fileExists(filename))
+            {
+                filename.clear();
+            }
+        }
+
+        if (filename.empty())
+        {
+            filename = gDirUtilp->findFile(filename_default,
+                gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
+                gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
+        }
 
         LLViewerInput::Keys keys;
         LLSimpleXUIParser parser;
@@ -495,7 +523,16 @@ void LLKeyConflictHandler::saveToSettings()
                         binding.key = LLKeyboard::stringFromKey(data.mKey);
                     }
                     binding.mask = string_from_mask(data.mMask);
-                    binding.mouse.set(string_from_mouse(data.mMouse), true); //set() because 'optional', for compatibility purposes
+                    if (data.mMouse == CLICK_NONE)
+                    {
+                        binding.mouse.setProvided(false);
+                    }
+                    else
+                    {
+                        // set() because 'optional', for compatibility purposes
+                        // just copy old keys.xml and rename to key_bindings.xml, it should work
+                        binding.mouse.set(string_from_mouse(data.mMouse), true);
+                    }
                     binding.command = iter->first;
                     mode.bindings.add(binding);
                 }
@@ -534,11 +571,22 @@ void LLKeyConflictHandler::saveToSettings()
                 }
                 break;
             default:
+                LL_ERRS() << "Not implememted mode " << mLoadMode << LL_ENDL;
                 break;
             }
 
-            // write back to user's xml;
-            std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml");
+            if (temporary)
+            {
+                // write to temporary xml and use it for gViewerInput
+                filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_temporary);
+                mUsesTemporaryFile = true;
+                sTemporaryFileUseCount++;
+            }
+            else
+            {
+                // write back to user's xml and use it for gViewerInput
+                filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default);
+            }
 
             LLXMLNodePtr output_node = new LLXMLNode("keys", false);
             LLXUIParser parser;
@@ -562,7 +610,11 @@ void LLKeyConflictHandler::saveToSettings()
             }
         }
     }
-    mHasUnsavedChanges = false;
+
+    if (!temporary)
+    {
+        clearUnsavedChanges();
+    }
 }
 
 LLKeyData LLKeyConflictHandler::getDefaultControl(const std::string &control_name, U32 index)
@@ -702,17 +754,17 @@ void LLKeyConflictHandler::resetToDefaults()
 
 void LLKeyConflictHandler::clear()
 {
-    mHasUnsavedChanges = false;
+    clearUnsavedChanges();
     mControlsMap.clear();
     mDefaultsMap.clear();
 }
 
 void LLKeyConflictHandler::resetKeyboardBindings()
 {
-    std::string filename = gDirUtilp->findFile("key_bindings.xml",
+    std::string filename = gDirUtilp->findFile(filename_default,
         gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
         gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
-    
+
     gViewerInput.loadBindingsXML(filename);
 }
 
@@ -773,3 +825,32 @@ void LLKeyConflictHandler::registerTemporaryControl(const std::string &control_n
     type_data->mKeyBind.addKeyData(mouse, key, mask, false);
 }
 
+void LLKeyConflictHandler::clearUnsavedChanges()
+{
+    mHasUnsavedChanges = false;
+
+    if (mUsesTemporaryFile)
+    {
+        mUsesTemporaryFile = false;
+        sTemporaryFileUseCount--;
+        if (!sTemporaryFileUseCount)
+        {
+            clearTemporaryFile();
+        }
+        // else: might be usefull to overwrite content of temp file with defaults
+        // but at the moment there is no such need
+    }
+}
+
+//static
+void LLKeyConflictHandler::clearTemporaryFile()
+{
+    // At the moment single file needs five handlers (one per mode), so doing this
+    // will remove file for all hadlers
+    std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_temporary);
+    if (gDirUtilp->fileExists(filename))
+    {
+        LLFile::remove(filename);
+    }
+}
+
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index 5c3b860ec6..24843e875f 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -74,6 +74,7 @@ public:
 
     LLKeyConflictHandler();
     LLKeyConflictHandler(ESourceMode mode);
+    ~LLKeyConflictHandler();
 
     bool canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask);
     bool canHandleKey(const std::string &control_name, KEY key, MASK mask);
@@ -93,8 +94,14 @@ public:
     void loadFromControlSettings(const std::string &name);
     // Drops any changes loads controls with ones from 'saved settings' or from xml
     void loadFromSettings(ESourceMode load_mode);
+
     // Saves settings to 'saved settings' or to xml
-    void saveToSettings();
+    // If 'temporary' is set, function will save settings to temporary
+    // file and reload input from temporary file.
+    // 'temporary' does not support gSavedSettings, those are handled
+    // by preferences, so 'temporary' is such case will simply not
+    // reset mHasUnsavedChanges
+    void saveToSettings(bool temporary = false);
 
     LLKeyData getDefaultControl(const std::string &control_name, U32 data_index);
     // Resets keybinding to default variant from 'saved settings' or xml
@@ -125,10 +132,19 @@ private:
     // returns false in case user is trying to reuse control that can't be reassigned
     bool removeConflicts(const LLKeyData &data, const U32 &conlict_mask);
 
+    void clearUnsavedChanges();
+    static void clearTemporaryFile();
+
     control_map_t mControlsMap;
     control_map_t mDefaultsMap;
     bool mHasUnsavedChanges;
     ESourceMode mLoadMode;
+
+    // To implement 'apply immediately'+revert on cancel, class applies changes to temporary file
+    // but this only works for settings from keybndings files (key_bindings.xml)
+    // saved setting rely onto external mechanism of preferences floater
+    bool mUsesTemporaryFile;
+    static S32 sTemporaryFileUseCount;
 };
 
 
-- 
cgit v1.2.3


From acc6e53f25af92af493b5953404610c744ff73a3 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Thu, 31 Oct 2019 17:16:50 +0200
Subject: SL-6109 Fixed walk_to defaults and typo.

---
 indra/newview/app_settings/key_bindings.xml                   | 7 ++++++-
 indra/newview/skins/default/xui/en/control_table_contents.xml | 2 +-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml
index d0c25f3ed0..536199c696 100644
--- a/indra/newview/app_settings/key_bindings.xml
+++ b/indra/newview/app_settings/key_bindings.xml
@@ -31,8 +31,9 @@
     <binding key="SPACE" mask="NONE" command="stop_moving"/>
     <binding key="ENTER" mask="NONE" command="start_chat"/>
     <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
-    
+
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
+    <binding key="" mask="NONE" mouse="LMB" command="walk_to"/>
   </first_person>
   <third_person>
     <binding key="A" mask="NONE" command="turn_left"/>
@@ -126,6 +127,7 @@
     <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
+    <binding key="" mask="NONE" mouse="LMB" command="walk_to"/>
   </third_person>
 
   <!-- Basic editing camera control -->
@@ -184,6 +186,7 @@
     <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/>
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
+    <binding key="" mask="NONE" mouse="LMB" command="walk_to"/>
   </edit>
   <sitting>
     <binding key="A" mask="ALT" command="spin_around_cw"/>
@@ -281,6 +284,7 @@
     <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
+    <binding key="" mask="NONE" mouse="LMB" command="walk_to"/>
   </sitting>
   <edit_avatar>
     <!--Avatar editing camera controls-->
@@ -308,5 +312,6 @@
     <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
+    <binding key="" mask="NONE" mouse="LMB" command="walk_to"/>
   </edit_avatar>
 </keys>
diff --git a/indra/newview/skins/default/xui/en/control_table_contents.xml b/indra/newview/skins/default/xui/en/control_table_contents.xml
index f078e80dff..288075628c 100644
--- a/indra/newview/skins/default/xui/en/control_table_contents.xml
+++ b/indra/newview/skins/default/xui/en/control_table_contents.xml
@@ -6,7 +6,7 @@
      name="lst_action" />
     <columns
      relative_width="0.22"
-     label="Prymary Control"
+     label="Primary Control"
      name="lst_ctrl1" />
     <columns
      relative_width="0.22"
-- 
cgit v1.2.3


From 65f2c039237b0c538134c17e7958090dc40d4559 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Mon, 4 Nov 2019 15:48:45 +0200
Subject: SL-6109 - Fixed defaults not restoring reliably - Fixed temporary
 changes not lifting reliably - Fixed switching modes was dropping changes to
 mode we switch to

---
 indra/newview/llappviewer.cpp                      |  2 +-
 indra/newview/llfloaterpreference.cpp              | 15 +++++--
 indra/newview/llfloaterpreference.h                |  2 +
 indra/newview/llkeyconflict.cpp                    | 47 +++++++++++++++++-----
 indra/newview/llkeyconflict.h                      | 15 ++++---
 .../default/xui/en/panel_preferences_controls.xml  |  1 +
 6 files changed, 62 insertions(+), 20 deletions(-)

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 96e77410c3..a4703d1eb1 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1012,7 +1012,7 @@ bool LLAppViewer::init()
 		key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "key_bindings.xml");
 		if (!gViewerInput.loadBindingsXML(key_bindings_file))
 		{
-			LL_ERRS("InitInfo") << "Unable to open default key bindings from" << key_bindings_file << LL_ENDL;
+			LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL;
 		}
 	}
 
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 9305f38a29..ffd83a8555 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2669,6 +2669,7 @@ LLPanelPreferenceControls::LLPanelPreferenceControls()
     mEditingColumn(-1),
     mEditingMode(0)
 {
+    // MODE_COUNT - 1 because there are currently no settings assigned to 'saved settings'.
     for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
     {
         mConflictHandler[i].setLoadMode((LLKeyConflictHandler::ESourceMode)i);
@@ -2908,17 +2909,25 @@ void LLPanelPreferenceControls::onListCommit()
 
 void LLPanelPreferenceControls::onModeCommit()
 {
-    regenerateControls();
+    mEditingMode = pKeyModeBox->getValue().asInteger();
+    if (mConflictHandler[mEditingMode].empty())
+    {
+        // opening for first time
+        mConflictHandler[mEditingMode].loadFromSettings((LLKeyConflictHandler::ESourceMode)mEditingMode);
+    }
+    populateControlTable();
 }
 
 void LLPanelPreferenceControls::onRestoreDefaults()
 {
     for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
     {
-        mConflictHandler[mEditingMode].resetToDefaults();
+        mConflictHandler[i].resetToDefaults();
         // Apply changes to viewer as 'temporary'
-        mConflictHandler[mEditingMode].saveToSettings(true);
+        mConflictHandler[i].saveToSettings(true);
     }
+
+    updateTable();
 }
 
 // todo: copy onSetKeyBind to interface and inherit from interface
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index f08f2aa2ba..112784b83e 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -307,7 +307,9 @@ public:
 	/*virtual*/ void onCancelKeyBind();
 
 private:
+	// reloads settings, discards current changes, updates table
 	void regenerateControls();
+
 	void populateControlTable();
 	void addSeparator();
 	void updateTable();
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index d88038816b..d9c2b3d53a 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -149,6 +149,7 @@ LLKeyConflictHandler::LLKeyConflictHandler(ESourceMode mode)
 LLKeyConflictHandler::~LLKeyConflictHandler()
 {
     clearUnsavedChanges();
+    // Note: does not reset bindings if temporary file was used
 }
 
 bool LLKeyConflictHandler::canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask)
@@ -579,13 +580,17 @@ void LLKeyConflictHandler::saveToSettings(bool temporary)
             {
                 // write to temporary xml and use it for gViewerInput
                 filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_temporary);
-                mUsesTemporaryFile = true;
-                sTemporaryFileUseCount++;
+                if (!mUsesTemporaryFile)
+                {
+                    mUsesTemporaryFile = true;
+                    sTemporaryFileUseCount++;
+                }
             }
             else
             {
                 // write back to user's xml and use it for gViewerInput
                 filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default);
+                // Don't reset mUsesTemporaryFile, it will be reset at cleanup stage
             }
 
             LLXMLNodePtr output_node = new LLXMLNode("keys", false);
@@ -606,6 +611,10 @@ void LLKeyConflictHandler::saveToSettings(bool temporary)
             // Now force a rebind for keyboard
             if (gDirUtilp->fileExists(filename))
             {
+                // Ideally instead of rebinding immediately we should shedule
+                // the rebind since single file can have multiple handlers,
+                // one per mode, saving simultaneously.
+                // Or whatever uses LLKeyConflictHandler should control the process.
                 gViewerInput.loadBindingsXML(filename);
             }
         }
@@ -613,6 +622,7 @@ void LLKeyConflictHandler::saveToSettings(bool temporary)
 
     if (!temporary)
     {
+        // will remove any temporary file if there were any
         clearUnsavedChanges();
     }
 }
@@ -754,18 +764,29 @@ void LLKeyConflictHandler::resetToDefaults()
 
 void LLKeyConflictHandler::clear()
 {
-    clearUnsavedChanges();
+    if (clearUnsavedChanges())
+    {
+        // temporary file was removed, this means we were using it and need to reload keyboard's bindings
+        resetKeyboardBindings();
+    }
     mControlsMap.clear();
     mDefaultsMap.clear();
 }
 
+// static
 void LLKeyConflictHandler::resetKeyboardBindings()
 {
-    std::string filename = gDirUtilp->findFile(filename_default,
-        gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
-        gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
-
-    gViewerInput.loadBindingsXML(filename);
+    // Try to load User's bindings first
+    std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default);
+    if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file))
+    {
+        // Failed to load custom bindings, try default ones
+        key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, filename_default);
+        if (!gViewerInput.loadBindingsXML(key_bindings_file))
+        {
+            LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL;
+        }
+    }
 }
 
 void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode)
@@ -825,8 +846,9 @@ void LLKeyConflictHandler::registerTemporaryControl(const std::string &control_n
     type_data->mKeyBind.addKeyData(mouse, key, mask, false);
 }
 
-void LLKeyConflictHandler::clearUnsavedChanges()
+bool LLKeyConflictHandler::clearUnsavedChanges()
 {
+    bool result = false;
     mHasUnsavedChanges = false;
 
     if (mUsesTemporaryFile)
@@ -835,15 +857,16 @@ void LLKeyConflictHandler::clearUnsavedChanges()
         sTemporaryFileUseCount--;
         if (!sTemporaryFileUseCount)
         {
-            clearTemporaryFile();
+            result = clearTemporaryFile();
         }
         // else: might be usefull to overwrite content of temp file with defaults
         // but at the moment there is no such need
     }
+    return result;
 }
 
 //static
-void LLKeyConflictHandler::clearTemporaryFile()
+bool LLKeyConflictHandler::clearTemporaryFile()
 {
     // At the moment single file needs five handlers (one per mode), so doing this
     // will remove file for all hadlers
@@ -851,6 +874,8 @@ void LLKeyConflictHandler::clearTemporaryFile()
     if (gDirUtilp->fileExists(filename))
     {
         LLFile::remove(filename);
+        return true;
     }
+    return false;
 }
 
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index 24843e875f..4ebe054f22 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -97,11 +97,11 @@ public:
 
     // Saves settings to 'saved settings' or to xml
     // If 'temporary' is set, function will save settings to temporary
-    // file and reload input from temporary file.
+    // file and reload input bindings from temporary file.
     // 'temporary' does not support gSavedSettings, those are handled
     // by preferences, so 'temporary' is such case will simply not
     // reset mHasUnsavedChanges
-    void saveToSettings(bool temporary = false);
+    void saveToSettings(bool apply_temporary = false);
 
     LLKeyData getDefaultControl(const std::string &control_name, U32 data_index);
     // Resets keybinding to default variant from 'saved settings' or xml
@@ -113,6 +113,10 @@ public:
     bool empty() { return mControlsMap.empty(); }
     void clear();
 
+    // reloads bindings from last valid user's xml or from default xml
+    // to keyboard's handler
+    static void resetKeyboardBindings();
+
     bool hasUnsavedChanges() { return mHasUnsavedChanges; }
     void setLoadMode(ESourceMode mode) { mLoadMode = mode; }
     ESourceMode getLoadMode() { return mLoadMode; }
@@ -127,13 +131,14 @@ private:
     typedef std::map<std::string, LLKeyConflict> control_map_t;
     void loadFromSettings(const LLViewerInput::KeyMode& keymode, control_map_t *destination);
     bool loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination);
-    void resetKeyboardBindings();
     void generatePlaceholders(ESourceMode load_mode); //E.x. non-assignable values
     // returns false in case user is trying to reuse control that can't be reassigned
     bool removeConflicts(const LLKeyData &data, const U32 &conlict_mask);
 
-    void clearUnsavedChanges();
-    static void clearTemporaryFile();
+    // removes flags and removes temporary file, returns 'true' if file was removed
+    bool clearUnsavedChanges();
+    // return true if there was a file to remove
+    static bool clearTemporaryFile();
 
     control_map_t mControlsMap;
     control_map_t mDefaultsMap;
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
index eca3c550d5..bd39343093 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
@@ -47,6 +47,7 @@
    height="23"
    width="110"
    label="Restore Default"
+   tooltip="Restores default values for all control modes."
    name="restore_defaults"/>
 
   <scroll_list
-- 
cgit v1.2.3


From 6ba0b97c851db7822e17a5a8dbb2d0964ca835f7 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Thu, 7 Nov 2019 20:09:25 +0200
Subject: SL-6109 - Edit mode appears to be obsolete and is not used, cleaned
 up - Improved ability to set defaults - Improved some labels - Made buttons
 bigger to accomodate languages with longer descriptions - Added ability to
 assign key for all modes simultaneously

---
 indra/newview/app_settings/key_bindings.xml        | 60 ---------------
 indra/newview/llfloaterpreference.cpp              | 85 ++++++++++++++++++----
 indra/newview/llfloaterpreference.h                |  7 +-
 indra/newview/llkeyconflict.cpp                    | 13 ----
 indra/newview/llkeyconflict.h                      |  1 -
 indra/newview/llsetkeybinddialog.cpp               | 12 +--
 indra/newview/llsetkeybinddialog.h                 |  7 +-
 indra/newview/llviewerinput.cpp                    |  7 --
 indra/newview/llviewerinput.h                      |  2 -
 .../skins/default/xui/en/floater_select_key.xml    |  8 +-
 .../newview/skins/default/xui/en/notifications.xml | 13 ++++
 .../default/xui/en/panel_preferences_controls.xml  | 18 ++---
 12 files changed, 104 insertions(+), 129 deletions(-)

diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml
index 536199c696..dd74293644 100644
--- a/indra/newview/app_settings/key_bindings.xml
+++ b/indra/newview/app_settings/key_bindings.xml
@@ -129,65 +129,6 @@
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
     <binding key="" mask="NONE" mouse="LMB" command="walk_to"/>
   </third_person>
-
-  <!-- Basic editing camera control -->
-  <edit>
-    <binding key="A" mask="NONE" command="spin_around_cw"/>
-    <binding key="D" mask="NONE" command="spin_around_ccw"/>
-    <binding key="W" mask="NONE" command="move_forward"/>
-    <binding key="S" mask="NONE" command="move_backward"/>
-    <binding key="E" mask="NONE" command="spin_over"/>
-    <binding key="C" mask="NONE" command="spin_under"/>
-    <binding key="ENTER" mask="NONE" command="start_chat"/>
-    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
-    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
-
-    <binding key="LEFT" mask="NONE" command="spin_around_cw"/>
-    <binding key="RIGHT" mask="NONE" command="spin_around_ccw"/>
-    <binding key="UP" mask="NONE" command="move_forward"/>
-    <binding key="DOWN" mask="NONE" command="move_backward"/>
-    <binding key="PGUP" mask="NONE" command="spin_over"/>
-    <binding key="PGDN" mask="NONE" command="spin_under"/>
-
-    <binding key="A" mask="SHIFT" command="pan_left"/>
-    <binding key="D" mask="SHIFT" command="pan_right"/>
-    <binding key="W" mask="SHIFT" command="pan_up"/>
-    <binding key="S" mask="SHIFT" command="pan_down"/>
-
-    <binding key="LEFT" mask="SHIFT" command="pan_left"/>
-    <binding key="RIGHT" mask="SHIFT" command="pan_right"/>
-    <binding key="UP" mask="SHIFT" command="pan_up"/>
-    <binding key="DOWN" mask="SHIFT" command="pan_down"/>
-
-    <!--Walking works with ALT held down.-->
-    <binding key="A" mask="ALT" command="slide_left"/>
-    <binding key="D" mask="ALT" command="slide_right"/>
-    <binding key="W" mask="ALT" command="push_forward"/>
-    <binding key="S" mask="ALT" command="push_backward"/>
-    <binding key="E" mask="ALT" command="jump"/>
-    <binding key="C" mask="ALT" command="push_down"/>
-
-    <binding key="LEFT" mask="ALT" command="slide_left"/>
-    <binding key="RIGHT" mask="ALT" command="slide_right"/>
-    <binding key="UP" mask="ALT" command="push_forward"/>
-    <binding key="DOWN" mask="ALT" command="push_backward"/>
-    <binding key="PGUP" mask="ALT" command="jump"/>
-    <binding key="PGDN" mask="ALT" command="push_down"/>
-    <binding key="HOME" mask="ALT" command="toggle_fly"/>
-
-    <binding key="PAD_LEFT" mask="ALT" command="slide_left"/>
-    <binding key="PAD_RIGHT" mask="ALT" command="slide_right"/>
-    <binding key="PAD_UP" mask="ALT" command="push_forward"/>
-    <binding key="PAD_DOWN" mask="ALT" command="push_backward"/>
-    <binding key="PAD_PGUP" mask="ALT" command="jump"/>
-    <binding key="PAD_PGDN" mask="ALT" command="push_down"/>
-    <binding key="PAD_ENTER" mask="ALT" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/>
-
-    <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
-    <binding key="" mask="NONE" mouse="LMB" command="walk_to"/>
-  </edit>
   <sitting>
     <binding key="A" mask="ALT" command="spin_around_cw"/>
     <binding key="D" mask="ALT" command="spin_around_ccw"/>
@@ -312,6 +253,5 @@
     <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
-    <binding key="" mask="NONE" mouse="LMB" command="walk_to"/>
   </edit_avatar>
 </keys>
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index ffd83a8555..98f4881eb6 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2688,7 +2688,7 @@ BOOL LLPanelPreferenceControls::postBuild()
 
     pControlsTable->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onListCommit, this));
     pKeyModeBox->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onModeCommit, this));
-    getChild<LLButton>("restore_defaults")->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onRestoreDefaults, this));
+    getChild<LLButton>("restore_defaults")->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onRestoreDefaultsBtn, this));
 
     return TRUE;
 }
@@ -2710,7 +2710,6 @@ void LLPanelPreferenceControls::populateControlTable()
     {
     case LLKeyConflictHandler::MODE_THIRD_PERSON:
     case LLKeyConflictHandler::MODE_FIRST_PERSON:
-    case LLKeyConflictHandler::MODE_EDIT:
     case LLKeyConflictHandler::MODE_EDIT_AVATAR:
     case LLKeyConflictHandler::MODE_SITTING:
         filename = "control_table_contents.xml";
@@ -2918,20 +2917,42 @@ void LLPanelPreferenceControls::onModeCommit()
     populateControlTable();
 }
 
-void LLPanelPreferenceControls::onRestoreDefaults()
+void LLPanelPreferenceControls::onRestoreDefaultsBtn()
 {
-    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
+    LLNotificationsUtil::add("PreferenceControlsDefaults", LLSD(), LLSD(), boost::bind(&LLPanelPreferenceControls::onRestoreDefaultsResponse, this, _1, _2));
+}
+
+void LLPanelPreferenceControls::onRestoreDefaultsResponse(const LLSD& notification, const LLSD& response)
+{
+    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+    switch(option)
     {
-        mConflictHandler[i].resetToDefaults();
+    case 0: // All
+        for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
+        {
+            mConflictHandler[i].resetToDefaults();
+            // Apply changes to viewer as 'temporary'
+            mConflictHandler[i].saveToSettings(true);
+        }
+
+        updateTable();
+        break;
+    case 1: // Current
+        mConflictHandler[mEditingMode].resetToDefaults();
         // Apply changes to viewer as 'temporary'
-        mConflictHandler[i].saveToSettings(true);
-    }
+        mConflictHandler[mEditingMode].saveToSettings(true);
 
-    updateTable();
+        updateTable();
+        break;
+    case 2: // Cancel
+    default:
+        //exit;
+        break;
+    }
 }
 
 // todo: copy onSetKeyBind to interface and inherit from interface
-bool LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore_mask)
+bool LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes)
 {
     if (!mConflictHandler[mEditingMode].canAssignControl(mEditingControl))
     {
@@ -2940,16 +2961,32 @@ bool LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MAS
 
     if ( mEditingColumn > 0)
     {
-        mConflictHandler[mEditingMode].registerControl(mEditingControl, mEditingColumn - 1, click, key, mask, true);
-        // Apply changes to viewer as 'temporary'
-        mConflictHandler[mEditingMode].saveToSettings(true);
+        if (all_modes)
+        {
+            for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
+            {
+                if (mConflictHandler[i].empty())
+                {
+                    mConflictHandler[i].loadFromSettings((LLKeyConflictHandler::ESourceMode)i);
+                }
+                mConflictHandler[i].registerControl(mEditingControl, mEditingColumn - 1, click, key, mask, true);
+                // Apply changes to viewer as 'temporary'
+                mConflictHandler[i].saveToSettings(true);
+            }
+        }
+        else
+        {
+            mConflictHandler[mEditingMode].registerControl(mEditingControl, mEditingColumn - 1, click, key, mask, true);
+            // Apply changes to viewer as 'temporary'
+            mConflictHandler[mEditingMode].saveToSettings(true);
+        }
     }
 
     updateTable();
     return true;
 }
 
-void LLPanelPreferenceControls::onDefaultKeyBind()
+void LLPanelPreferenceControls::onDefaultKeyBind(bool all_modes)
 {
     if (!mConflictHandler[mEditingMode].canAssignControl(mEditingControl))
     {
@@ -2958,9 +2995,25 @@ void LLPanelPreferenceControls::onDefaultKeyBind()
     
     if (mEditingColumn > 0)
     {
-        mConflictHandler[mEditingMode].resetToDefault(mEditingControl, mEditingColumn - 1);
-        // Apply changes to viewer as 'temporary'
-        mConflictHandler[mEditingMode].saveToSettings(true);
+        if (all_modes)
+        {
+            for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
+            {
+                if (mConflictHandler[i].empty())
+                {
+                    mConflictHandler[i].loadFromSettings((LLKeyConflictHandler::ESourceMode)i);
+                }
+                mConflictHandler[i].resetToDefault(mEditingControl, mEditingColumn - 1);
+                // Apply changes to viewer as 'temporary'
+                mConflictHandler[i].saveToSettings(true);
+            }
+        }
+        else
+        {
+            mConflictHandler[mEditingMode].resetToDefault(mEditingControl, mEditingColumn - 1);
+            // Apply changes to viewer as 'temporary'
+            mConflictHandler[mEditingMode].saveToSettings(true);
+        }
     }
     updateTable();
 }
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 112784b83e..9ede7d5bcf 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -301,9 +301,10 @@ public:
 
 	void onListCommit();
 	void onModeCommit();
-	void onRestoreDefaults();
-	/*virtual*/ bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore_mask);
-	/*virtual*/ void onDefaultKeyBind();
+	void onRestoreDefaultsBtn();
+	void onRestoreDefaultsResponse(const LLSD& notification, const LLSD& response);
+	/*virtual*/ bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes);
+    /*virtual*/ void onDefaultKeyBind(bool all_modes);
 	/*virtual*/ void onCancelKeyBind();
 
 private:
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index d9c2b3d53a..b4f5ec4d57 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -345,13 +345,6 @@ bool LLKeyConflictHandler::loadFromSettings(const ESourceMode &load_mode, const
                 res = true;
             }
             break;
-        case MODE_EDIT:
-            if (keys.edit.isProvided())
-            {
-                loadFromSettings(keys.edit, destination);
-                res = true;
-            }
-            break;
         case MODE_EDIT_AVATAR:
             if (keys.edit_avatar.isProvided())
             {
@@ -553,12 +546,6 @@ void LLKeyConflictHandler::saveToSettings(bool temporary)
                     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())
                 {
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index 4ebe054f22..48af0ccdfe 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -59,7 +59,6 @@ public:
     {
         MODE_FIRST_PERSON,
         MODE_THIRD_PERSON,
-        MODE_EDIT,
         MODE_EDIT_AVATAR,
         MODE_SITTING,
         MODE_SAVED_SETTINGS, // for settings from saved settings
diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp
index 806c70aa03..8d0d71daaf 100644
--- a/indra/newview/llsetkeybinddialog.cpp
+++ b/indra/newview/llsetkeybinddialog.cpp
@@ -86,7 +86,7 @@ BOOL LLSetKeyBindDialog::postBuild()
     childSetAction("Cancel", onCancel, this);
     getChild<LLUICtrl>("Cancel")->setFocus(TRUE);
 
-    pCheckBox = getChild<LLCheckBoxCtrl>("ignore_masks");
+    pCheckBox = getChild<LLCheckBoxCtrl>("apply_all");
     pDesription = getChild<LLTextBase>("descritption");
 
     gFocusMgr.setKeystrokesOnly(TRUE);
@@ -148,10 +148,6 @@ void LLSetKeyBindDialog::setParent(LLKeyBindResponderInterface* parent, LLView*
     }
     pDesription->setText(getString("basic_description"));
     pDesription->setTextArg("[INPUT]", input);
-
-    bool can_ignore_masks = (key_mask & CAN_IGNORE_MASKS) != 0;
-    pCheckBox->setVisible(can_ignore_masks);
-    pCheckBox->setValue(false);
 }
 
 // static
@@ -308,7 +304,7 @@ void LLSetKeyBindDialog::onDefault(void* user_data)
     LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
     if (self->pParent)
     {
-        self->pParent->onDefaultKeyBind();
+        self->pParent->onDefaultKeyBind(self->pCheckBox->getValue().asBoolean());
         self->pParent = NULL;
     }
     self->closeFloater();
@@ -326,11 +322,11 @@ void LLSetKeyBindDialog::onClickTimeout(void* user_data, MASK mask)
     self->closeFloater();
 }
 
-void LLSetKeyBindDialog::setKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore)
+void LLSetKeyBindDialog::setKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes)
 {
     if (pParent)
     {
-        pParent->onSetKeyBind(click, key, mask, ignore);
+        pParent->onSetKeyBind(click, key, mask, all_modes);
         pParent = NULL;
     }
 }
diff --git a/indra/newview/llsetkeybinddialog.h b/indra/newview/llsetkeybinddialog.h
index 16a2d768e4..c7b4e3c364 100644
--- a/indra/newview/llsetkeybinddialog.h
+++ b/indra/newview/llsetkeybinddialog.h
@@ -40,7 +40,6 @@ 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 CAN_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;
 
 
@@ -50,9 +49,9 @@ public:
     virtual ~LLKeyBindResponderInterface() {};
 
     virtual void onCancelKeyBind() = 0;
-    virtual void onDefaultKeyBind() = 0;
+    virtual void onDefaultKeyBind(bool all_modes) = 0;
     // returns true if parent failed to set key due to key being in use
-    virtual bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore) = 0;
+    virtual bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes) = 0;
 };
 
 class LLSetKeyBindDialog : public LLModalDialog, public LLDrawFrustum
@@ -82,7 +81,7 @@ public:
 
 private:
     bool recordAndHandleKey(KEY key, MASK mask);
-    void setKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore);
+    void setKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes);
     LLKeyBindResponderInterface *pParent;
     LLCheckBoxCtrl *pCheckBox;
     LLTextBase *pDesription;
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index 50618350be..eaad5ab632 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -934,11 +934,6 @@ BOOL LLViewerInput::modeFromString(const std::string& string, S32 *mode) const
 		*mode = MODE_THIRD_PERSON;
 		return TRUE;
 	}
-	else if (string == "EDIT")
-	{
-		*mode = MODE_EDIT;
-		return TRUE;
-	}
 	else if (string == "EDIT_AVATAR")
 	{
 		*mode = MODE_EDIT_AVATAR;
@@ -1153,7 +1148,6 @@ LLViewerInput::KeyMode::KeyMode()
 LLViewerInput::Keys::Keys()
 :	first_person("first_person"),
 	third_person("third_person"),
-	edit("edit"),
 	sitting("sitting"),
 	edit_avatar("edit_avatar")
 {}
@@ -1180,7 +1174,6 @@ S32 LLViewerInput::loadBindingsXML(const std::string& filename)
 	{
 		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);
 	}
diff --git a/indra/newview/llviewerinput.h b/indra/newview/llviewerinput.h
index b7124a54b2..eff42600fd 100644
--- a/indra/newview/llviewerinput.h
+++ b/indra/newview/llviewerinput.h
@@ -65,7 +65,6 @@ typedef enum e_keyboard_mode
 {
 	MODE_FIRST_PERSON,
 	MODE_THIRD_PERSON,
-	MODE_EDIT,
 	MODE_EDIT_AVATAR,
 	MODE_SITTING,
 	MODE_COUNT
@@ -99,7 +98,6 @@ public:
 	{
 		Optional<KeyMode>	first_person,
 							third_person,
-							edit,
 							sitting,
 							edit_avatar;
 
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 255de60d00..48d9eee4cd 100644
--- a/indra/newview/skins/default/xui/en/floater_select_key.xml
+++ b/indra/newview/skins/default/xui/en/floater_select_key.xml
@@ -44,11 +44,11 @@ Allowed input: [INPUT].
      follows="top|left"
      height="20"
      initial_value="false"
-     label="Ignore extra accelerator keys"
+     label="Apply to all"
      layout="topleft"
-     left="28"
-     name="ignore_masks"
-     tool_tip="Ignore extra Shift, Alt and Ctrl keys. Example: This allows to hold W (forward, ignores shift) and Shift+A (slide left) simultaneously and agent will both move forward and slide left."
+     left="90"
+     name="apply_all"
+     tool_tip="Viewer uses different control combinations depending on what you are doing in world, setting this will apply your change to all combinations"
      top_pad="8"
      width="160" />
   
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index a757a4beaa..f2e6848e1a 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -11275,6 +11275,19 @@ Cannot create large prims that intersect other residents.  Please re-try when ot
      notext="Cancel"
      yestext="OK"/>
   </notification>
+  
+  <notification
+   icon="alertmodal.tga"
+   name="PreferenceControlsDefaults"
+   type="alertmodal">
+    Do you want to restore default values for controls?
+    <tag>confirm</tag>
+    <usetemplate
+       canceltext="Cancel"
+       name="yesnocancelbuttons"
+       notext="Current mode"
+       yestext="All modes"/>
+  </notification>
     
   <notification
    icon="alertmodal.tga"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
index bd39343093..0f830ef0c9 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <panel
  border="true"
  follows="all"
@@ -15,28 +15,24 @@
    top="6"
    left="10"
    height="23"
-   width="110"
+   width="140"
    name="key_mode">
     <combo_box.item
      label="Third Person "
      name="third_person"
      value="1"/>
     <combo_box.item
-     label="First Person "
+     label="First Person (Mouselook)"
      name="first_person"
      value="0"/>
-    <combo_box.item
-     label="Edit"
-     name="edit"
-     value="2"/>
     <combo_box.item
      label="Edit Avatar"
      name="edit_avatar"
-     value="3"/>
+     value="2"/>
     <combo_box.item
      label="Sitting"
      name="sitting"
-     value="4"/>
+     value="3"/>
   </combo_box>
 
   <button
@@ -45,8 +41,8 @@
    top="6"
    right="-10"
    height="23"
-   width="110"
-   label="Restore Default"
+   width="140"
+   label="Restore Defaults"
    tooltip="Restores default values for all control modes."
    name="restore_defaults"/>
 
-- 
cgit v1.2.3


From 8ca72557291b71853618a4e16f5ab193284c0e95 Mon Sep 17 00:00:00 2001
From: Ansariel Hiller <ansarielhiller@yahoo.de>
Date: Sat, 9 Nov 2019 15:06:09 +0000
Subject: Fix custom user keybindings not being displayed in preferences
 correctly

---
 indra/newview/llkeyconflict.cpp | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index b4f5ec4d57..121965a388 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -124,6 +124,10 @@ EMouseClickType mouse_from_string(const std::string& input)
     {
         return CLICK_BUTTON5;
     }
+    if (input == "Double LMB")
+    {
+        return CLICK_DOUBLELEFT;
+    }
     return CLICK_NONE;
 }
 
@@ -396,7 +400,7 @@ void LLKeyConflictHandler::loadFromSettings(ESourceMode load_mode)
 
         // load user's
         filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default);
-        if (!gDirUtilp->fileExists(filename) || loadFromSettings(load_mode, filename, &mControlsMap))
+        if (!gDirUtilp->fileExists(filename) || !loadFromSettings(load_mode, filename, &mControlsMap))
         {
             // mind placeholders
             mControlsMap.insert(mDefaultsMap.begin(), mDefaultsMap.end());
-- 
cgit v1.2.3


From 27808b4d64306e1850c15ab25d11ef80cc5ca817 Mon Sep 17 00:00:00 2001
From: Ansariel Hiller <ansarielhiller@yahoo.de>
Date: Sat, 9 Nov 2019 15:07:32 +0000
Subject: Fix double-tab run right not working properly

---
 indra/newview/llviewerinput.cpp | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index eaad5ab632..a267678bb3 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -730,11 +730,11 @@ bool run_right(EKeystate s)
         if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT)
         {
             gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_SLIDERIGHT;
-            if (!gAgent.getRunning())
-            {
-                gAgent.setRunning();
-                gAgent.sendWalkRun(true);
-            }
+        }
+        if (!gAgent.getRunning())
+        {
+            gAgent.setRunning();
+            gAgent.sendWalkRun(true);
         }
     }
     else if (KEYSTATE_UP == s)
-- 
cgit v1.2.3


From f3fdc4e999d17376ccc8441038f1c232af695836 Mon Sep 17 00:00:00 2001
From: Ansariel Hiller <ansarielhiller@yahoo.de>
Date: Sat, 9 Nov 2019 15:08:31 +0000
Subject: Only focus camera on agent in autopilot mode if the walk is actually
 performed

---
 indra/newview/lltoolpie.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index dc9c0edc0c..e7030a3f85 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -576,11 +576,11 @@ bool LLToolPie::walkToClickedLocation()
         mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE;
     }
 
-    gAgentCamera.setFocusOnAvatar(TRUE, TRUE);
-
     if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) ||
         (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero()))
     {
+        gAgentCamera.setFocusOnAvatar(TRUE, TRUE);
+
         if (mAutoPilotDestination) { mAutoPilotDestination->markDead(); }
         mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE);
         mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal);
-- 
cgit v1.2.3


From 77034bf1a93a025e33969bacb38482f47821261b Mon Sep 17 00:00:00 2001
From: Ansariel Hiller <ansarielhiller@yahoo.de>
Date: Sat, 9 Nov 2019 17:28:23 +0000
Subject: Save XUI parser warning

---
 indra/newview/skins/default/xui/en/panel_preferences_controls.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
index 0f830ef0c9..904387909e 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
@@ -43,7 +43,7 @@
    height="23"
    width="140"
    label="Restore Defaults"
-   tooltip="Restores default values for all control modes."
+   tool_tip="Restores default values for all control modes."
    name="restore_defaults"/>
 
   <scroll_list
-- 
cgit v1.2.3


From e8958a1c8921ec58653b1245be5dd767cfead6dd Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Sun, 10 Nov 2019 14:40:07 +0200
Subject: SL-6109 localization support for control table

---
 indra/newview/llfloaterpreference.cpp              | 23 +++++++++++++---------
 .../default/xui/en/control_table_contents.xml      |  4 ++++
 2 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 98f4881eb6..05de782838 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2720,21 +2720,26 @@ void LLPanelPreferenceControls::populateControlTable()
         return;
     }
 
-    std::string full_filename = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, filename);
-    LLSimpleXUIParser parser;
+    LLXMLNodePtr xmlNode;
     LLScrollListCtrl::Contents contents;
-    if (!parser.readXUI(full_filename, contents)
-        || !contents.validateBlock())
+    if (!LLUICtrlFactory::getLayeredXMLNode(filename, xmlNode))
+    {
+    LL_WARNS() << "Failed to load " << filename << LL_ENDL;
+    return;
+    }
+    LLXUIParser parser;
+    parser.readXUI(xmlNode, contents, filename);
+
+    if (!contents.validateBlock())
     {
-        LL_INFOS() << "Failed to load" << LL_ENDL;
         return;
     }
 
-    for (LLInitParam::ParamIterator<LLScrollListColumn::Params>::const_iterator row_it = contents.columns.begin();
-        row_it != contents.columns.end();
-        ++row_it)
+    for (LLInitParam::ParamIterator<LLScrollListColumn::Params>::const_iterator col_it = contents.columns.begin();
+        col_it != contents.columns.end();
+        ++col_it)
     {
-        pControlsTable->addColumn(*row_it);
+        pControlsTable->addColumn(*col_it);
     }
 
     LLScrollListCell::Params cell_params;
diff --git a/indra/newview/skins/default/xui/en/control_table_contents.xml b/indra/newview/skins/default/xui/en/control_table_contents.xml
index 288075628c..da9cceb2db 100644
--- a/indra/newview/skins/default/xui/en/control_table_contents.xml
+++ b/indra/newview/skins/default/xui/en/control_table_contents.xml
@@ -18,6 +18,7 @@
      name="lst_ctrl3" />
     <rows
      enabled="false"
+     name="move_actions"
      value="">
         <columns
          type="icontext"
@@ -202,6 +203,7 @@
     </rows>
     <rows
      enabled="false"
+     name="camera_actions"
      value="">
         <columns
          type="icontext"
@@ -424,6 +426,7 @@
     </rows>
     <rows
      enabled="false"
+     name="editing_actions"
      value="">
         <columns
          type="icontext"
@@ -502,6 +505,7 @@
     </rows>
     <rows
      enabled="false"
+     name="media_actions"
      value="">
         <columns
          type="icontext"
-- 
cgit v1.2.3


From 56105df3999cee7a86c4338d105358875967225a Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Sun, 10 Nov 2019 19:06:03 +0200
Subject: SL-6109 Better key and table localization support and fix for
 key-replacing

---
 indra/llcommon/llkeybind.cpp                       | 31 +++----------
 indra/llwindow/llkeyboard.cpp                      | 11 +++--
 indra/llwindow/llkeyboard.h                        |  2 +-
 indra/newview/llkeyconflict.cpp                    |  3 +-
 indra/newview/llkeyconflict.h                      |  1 +
 .../default/xui/en/control_table_contents.xml      | 52 ++++++++++++++++++++++
 6 files changed, 68 insertions(+), 32 deletions(-)

diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp
index 46a3230240..ecfc289cb3 100644
--- a/indra/llcommon/llkeybind.cpp
+++ b/indra/llcommon/llkeybind.cpp
@@ -340,43 +340,24 @@ bool LLKeyBind::addKeyData(const LLKeyData& data)
 
 void LLKeyBind::replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore, U32 index)
 {
-    if (mouse != CLICK_NONE || key != KEY_NONE )
-    {
-        // if both click and key are none, we are inserting a placeholder, we don't want to reset anything
-        // otherwise reset identical key
-        for (data_vector_t::iterator iter = mData.begin(); iter != mData.end(); iter++)
-        {
-            if (iter->mKey == key
-                && iter->mMouse == mouse
-                && iter->mIgnoreMasks == ignore
-                && (iter->mIgnoreMasks || iter->mMask == mask))
-            {
-                iter->reset();
-                break;
-            }
-        }
-    }
-    if (mData.size() > index)
-    {
-        mData[index] = LLKeyData(mouse, key, mask, ignore);
-    }
-    else
-    {
-        mData.push_back(LLKeyData(mouse, key, mask, ignore));
-    }
+    replaceKeyData(LLKeyData(mouse, key, mask, ignore), index);
 }
 
 void LLKeyBind::replaceKeyData(const LLKeyData& data, U32 index)
 {
     if (!data.isEmpty())
     {
+        // if both click and key are none (isEmpty()), we are inserting a placeholder, we don't want to reset anything
+        // otherwise reset identical key
         for (data_vector_t::iterator iter = mData.begin(); iter != mData.end(); iter++)
         {
             if (iter->mKey == data.mKey
                 && iter->mMouse == data.mMouse
                 && iter->mIgnoreMasks == data.mIgnoreMasks
-                && (iter->mIgnoreMasks || iter->mMask == data.mMask))
+                && iter->mMask == data.mMask)
             {
+                // Replacing only fully equal combinations even in case 'ignore' is set
+                // Reason: Simplicity and user might decide to do a 'move' command as W and Shift+Ctrl+W, and 'run' as Shift+W
                 iter->reset();
                 break;
             }
diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp
index 8e75325859..5404ac50e5 100644
--- a/indra/llwindow/llkeyboard.cpp
+++ b/indra/llwindow/llkeyboard.cpp
@@ -327,7 +327,7 @@ BOOL LLKeyboard::keyFromString(const std::string& str, KEY *key)
 
 
 // static
-std::string LLKeyboard::stringFromKey(KEY key)
+std::string LLKeyboard::stringFromKey(KEY key, bool translate)
 {
 	std::string res = get_if_there(sKeysToNames, key, std::string());
 	if (res.empty())
@@ -338,10 +338,13 @@ std::string LLKeyboard::stringFromKey(KEY key)
 		res = std::string(buffer);
 	}
 
-	LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator;
-	if (trans != NULL)
+	if (translate)
 	{
-		res = trans(res.c_str());
+		LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator;
+		if (trans != NULL)
+		{
+			res = trans(res.c_str());
+		}
 	}
 
 	return res;
diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h
index f6404164e7..36bd8bcbed 100644
--- a/indra/llwindow/llkeyboard.h
+++ b/indra/llwindow/llkeyboard.h
@@ -94,7 +94,7 @@ public:
 
 	static BOOL		maskFromString(const std::string& str, MASK *mask);		// False on failure
 	static BOOL		keyFromString(const std::string& str, KEY *key);			// False on failure
-	static std::string stringFromKey(KEY key);
+	static std::string stringFromKey(KEY key, bool translate = true);
 	static std::string stringFromAccelerator( MASK accel_mask ); // separated for convinience, returns with "+": "Shift+" or "Shift+Alt+"...
 	static std::string stringFromAccelerator( MASK accel_mask, KEY key );
 
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index 121965a388..882a1d0caf 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -517,8 +517,7 @@ void LLKeyConflictHandler::saveToSettings(bool temporary)
                     }
                     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.key = LLKeyboard::stringFromKey(data.mKey, false /*Do not localize*/);
                     }
                     binding.mask = string_from_mask(data.mMask);
                     if (data.mMouse == CLICK_NONE)
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index 48af0ccdfe..84730e4d4f 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -86,6 +86,7 @@ public:
 
     LLKeyData getControl(const std::string &control_name, U32 data_index);
 
+    // localized string
     static std::string getStringFromKeyData(const LLKeyData& keydata);
     std::string getControlString(const std::string &control_name, U32 data_index);
 
diff --git a/indra/newview/skins/default/xui/en/control_table_contents.xml b/indra/newview/skins/default/xui/en/control_table_contents.xml
index da9cceb2db..7b777befee 100644
--- a/indra/newview/skins/default/xui/en/control_table_contents.xml
+++ b/indra/newview/skins/default/xui/en/control_table_contents.xml
@@ -30,6 +30,7 @@
          value="Move_Walk_Off" />
     </rows>
     <rows
+     name="walk_to"
      value="walk_to">
         <columns
          column="lst_action"
@@ -40,6 +41,7 @@
          value="Walk to" />
     </rows>
     <rows
+     name="teleport_to"
      value="teleport_to">
         <columns
          column="lst_action"
@@ -50,6 +52,7 @@
          value="Teleport to" />
     </rows>
     <rows
+     name="push_forward"
      value="push_forward">
         <columns
          column="lst_action"
@@ -59,6 +62,7 @@
          value="Move Forward" />
     </rows>
     <rows
+     name="push_backward"
      value="push_backward">
         <columns
          column="lst_action"
@@ -68,6 +72,7 @@
          value="Move Backward" />
     </rows>
     <rows
+     name="turn_left"
      value="turn_left">
         <columns
          column="lst_action"
@@ -77,6 +82,7 @@
          value="Left" />
     </rows>
     <rows
+     name="turn_right"
      value="turn_right">
         <columns
          column="lst_action"
@@ -86,6 +92,7 @@
          value="Right" />
     </rows>
     <rows
+     name="slide_left"
      value="slide_left">
         <columns
          column="lst_action"
@@ -95,6 +102,7 @@
          value="Strafe left" />
     </rows>
     <rows
+     name="slide_right"
      value="slide_right">
         <columns
          column="lst_action"
@@ -104,6 +112,7 @@
          value="Strafe right" />
     </rows>
     <rows
+     name="jump"
      value="jump">
         <columns
          column="lst_action"
@@ -113,6 +122,7 @@
          value="Jump/Up" />
     </rows>
     <rows
+     name="push_down"
      value="push_down">
         <columns
          column="lst_action"
@@ -122,6 +132,7 @@
          value="Down" />
     </rows>
     <rows
+     name="run_forward"
      value="run_forward">
         <columns
          column="lst_action"
@@ -131,6 +142,7 @@
          value="Run Forward" />
     </rows>
     <rows
+     name="run_backward"
      value="run_backward">
         <columns
          column="lst_action"
@@ -140,6 +152,7 @@
          value="Run Backward" />
     </rows>
     <rows
+     name="run_left"
      value="run_left">
         <columns
          column="lst_action"
@@ -149,6 +162,7 @@
          value="Run Left" />
     </rows>
     <rows
+     name="run_right"
      value="run_right">
         <columns
          column="lst_action"
@@ -158,6 +172,7 @@
          value="Run Right" />
     </rows>
     <rows
+     name="toggle_run"
      value="toggle_run">
         <columns
          column="lst_action"
@@ -167,6 +182,7 @@
          value="Toggle Run" />
     </rows>
     <rows
+     name="toggle_fly"
      value="toggle_fly">
         <columns
          column="lst_action"
@@ -176,6 +192,7 @@
          value="Fly/Stop flying" />
     </rows>
     <rows
+     name="toggle_sit"
      value="toggle_sit">
         <columns
          column="lst_action"
@@ -185,6 +202,7 @@
          value="Sit/Stand" />
     </rows>
     <rows
+     name="stop_moving"
      value="stop_moving">
         <columns
          column="lst_action"
@@ -215,6 +233,7 @@
          value="Cam_FreeCam_Off" />
     </rows>
     <rows
+     name="look_up"
      value="look_up">
         <columns
          column="lst_action"
@@ -224,6 +243,7 @@
          value="Look Up" />
     </rows>
     <rows
+     name="look_down"
      value="look_down">
         <columns
          column="lst_action"
@@ -233,6 +253,7 @@
          value="Look Down" />
     </rows>
     <rows
+     name="move_forward"
      value="move_forward">
         <columns
          column="lst_action"
@@ -242,6 +263,7 @@
          value="Camera Forward" />
     </rows>
     <rows
+     name="move_backward"
      value="move_backward">
         <columns
          column="lst_action"
@@ -251,6 +273,7 @@
          value="Camera Backward" />
     </rows>
     <rows
+     name="move_forward_fast"
      value="move_forward_fast">
         <columns
          column="lst_action"
@@ -260,6 +283,7 @@
          value="Camera Forward Fast" />
     </rows>
     <rows
+     name="move_backward_fast"
      value="move_backward_fast">
         <columns
          column="lst_action"
@@ -269,6 +293,7 @@
          value="Camera Backward Fast" />
     </rows>
     <rows
+     name="move_forward_sitting"
      value="move_forward_sitting">
         <columns
          column="lst_action"
@@ -278,6 +303,7 @@
          value="Camera Forward Sitting" />
     </rows>
     <rows
+     name="move_backward_sitting"
      value="move_backward_sitting">
         <columns
          column="lst_action"
@@ -287,6 +313,7 @@
          value="Camera Backward Sitting" />
     </rows>
     <rows
+     name="spin_over"
      value="spin_over">
         <columns
          column="lst_action"
@@ -296,6 +323,7 @@
          value="Camera Spin Over" />
     </rows>
     <rows
+     name="spin_under"
      value="spin_under">
         <columns
          column="lst_action"
@@ -305,6 +333,7 @@
          value="Camera Spin Under" />
     </rows>
     <rows
+     name="spin_over_sitting"
      value="spin_over_sitting">
         <columns
          column="lst_action"
@@ -314,6 +343,7 @@
          value="Camera Spin Over" />
     </rows>
     <rows
+     name="spin_under_sitting"
      value="spin_under_sitting">
         <columns
          column="lst_action"
@@ -323,6 +353,7 @@
          value="Camera Spin Under" />
     </rows>
     <rows
+     name="pan_up"
      value="pan_up">
         <columns
          column="lst_action"
@@ -332,6 +363,7 @@
          value="Camera Pan Up" />
     </rows>
     <rows
+     name="pan_down"
      value="pan_down">
         <columns
          column="lst_action"
@@ -341,6 +373,7 @@
          value="Camera Pan Down" />
     </rows>
     <rows
+     name="pan_left"
      value="pan_left">
         <columns
          column="lst_action"
@@ -350,6 +383,7 @@
          value="Camera Pan Left" />
     </rows>
     <rows
+     name="pan_right"
      value="pan_right">
         <columns
          column="lst_action"
@@ -359,6 +393,7 @@
          value="Camera Pan Right" />
     </rows>
     <rows
+     name="pan_in"
      value="pan_in">
         <columns
          column="lst_action"
@@ -368,6 +403,7 @@
          value="Camera Pan In" />
     </rows>
     <rows
+     name="pan_out"
      value="pan_out">
         <columns
          column="lst_action"
@@ -377,6 +413,7 @@
          value="Camera Pan Out" />
     </rows>
     <rows
+     name="spin_around_ccw"
      value="spin_around_ccw">
         <columns
          column="lst_action"
@@ -387,6 +424,7 @@
          value="Counterclockwise" />
     </rows>
     <rows
+     name="spin_around_cw"
      value="spin_around_cw">
         <columns
          column="lst_action"
@@ -397,6 +435,7 @@
          value="Clockwise" />
     </rows>
     <rows
+     name="spin_around_ccw_sitting"
      value="spin_around_ccw_sitting">
         <columns
          column="lst_action"
@@ -407,6 +446,7 @@
          value="Counterclockwise Sitting" />
     </rows>
     <rows
+     name="spin_around_cw_sitting"
      value="spin_around_cw_sitting">
         <columns
          column="lst_action"
@@ -438,6 +478,7 @@
          value="Tool_Dozer" />
     </rows>
     <rows
+     name="edit_avatar_spin_ccw"
      value="edit_avatar_spin_ccw">
         <columns
          column="lst_action"
@@ -448,6 +489,7 @@
          value="Counterclockwise" />
     </rows>
     <rows
+     name="edit_avatar_spin_cw"
      value="edit_avatar_spin_cw">
         <columns
          column="lst_action"
@@ -458,6 +500,7 @@
          value="Clockwise" />
     </rows>
     <rows
+     name="edit_avatar_spin_over"
      value="edit_avatar_spin_over">
         <columns
          column="lst_action"
@@ -468,6 +511,7 @@
          value="Camera Spin Over" />
     </rows>
     <rows
+     name="edit_avatar_spin_under"
      value="edit_avatar_spin_under">
         <columns
          column="lst_action"
@@ -478,6 +522,7 @@
          value="Camera Spin Under" />
     </rows>
     <rows
+     name="edit_avatar_move_forward"
      value="edit_avatar_move_forward">
         <columns
          column="lst_action"
@@ -487,6 +532,7 @@
          value="Camera Forward" />
     </rows>
     <rows
+     name="edit_avatar_move_backward"
      value="edit_avatar_move_backward">
         <columns
          column="lst_action"
@@ -517,6 +563,7 @@
          value="Audio_Press" />
     </rows>
     <rows
+     name="toggle_pause_media"
      value="toggle_pause_media">
         <columns
          column="lst_action"
@@ -526,6 +573,7 @@
          value="Play/Pause Media" />
     </rows>
     <rows
+     name="toggle_enable_media"
      value="toggle_enable_media">
         <columns
          column="lst_action"
@@ -535,6 +583,7 @@
          value="Play/Stop All Media" />
     </rows>
     <rows
+     name="voice_follow_key"
      value="voice_follow_key">
         <columns
          column="lst_action"
@@ -544,6 +593,7 @@
          value="Voice" />
     </rows>
     <rows
+     name="toggle_voice"
      value="toggle_voice">
         <columns
          column="lst_action"
@@ -553,6 +603,7 @@
          value="Toggle Voice" />
     </rows>
     <rows
+     name="start_chat"
      value="start_chat">
         <columns
          column="lst_action"
@@ -562,6 +613,7 @@
          value="Start Chat" />
     </rows>
     <rows
+     name="start_gesture"
      value="start_gesture">
         <columns
          column="lst_action"
-- 
cgit v1.2.3


From 679a0d752193c757b70e39ad4408fa8492ad47f9 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Mon, 11 Nov 2019 19:43:29 +0200
Subject: Backed out changeset: 19f3fa6e3e63

---
 indra/newview/CMakeLists.txt                |   2 -
 indra/newview/lldrawfrustum.cpp             | 113 ----------------------------
 indra/newview/lldrawfrustum.h               |  55 --------------
 indra/newview/llfloateravatarpicker.cpp     |  75 +++++++++++++++++-
 indra/newview/llfloateravatarpicker.h       |   9 ++-
 indra/newview/llfloatercolorpicker.cpp      |  59 ++++++++++++++-
 indra/newview/llfloatercolorpicker.h        |  11 ++-
 indra/newview/llfloaterexperiencepicker.cpp |  72 +++++++++++++++++-
 indra/newview/llfloaterexperiencepicker.h   |  10 ++-
 indra/newview/lltexturectrl.cpp             |  62 ++++++++++++++-
 indra/newview/lltexturectrl.h               |   6 +-
 11 files changed, 280 insertions(+), 194 deletions(-)
 delete mode 100644 indra/newview/lldrawfrustum.cpp
 delete mode 100644 indra/newview/lldrawfrustum.h

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index cbd2dd8b2f..5a872f2aac 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -179,7 +179,6 @@ set(viewer_SOURCE_FILES
     lldonotdisturbnotificationstorage.cpp
     lldndbutton.cpp
     lldrawable.cpp
-    lldrawfrustum.cpp
     lldrawpool.cpp
     lldrawpoolalpha.cpp
     lldrawpoolavatar.cpp
@@ -809,7 +808,6 @@ set(viewer_HEADER_FILES
     lldonotdisturbnotificationstorage.h
     lldndbutton.h
     lldrawable.h
-    lldrawfrustum.h
     lldrawpool.h
     lldrawpoolalpha.h
     lldrawpoolavatar.h
diff --git a/indra/newview/lldrawfrustum.cpp b/indra/newview/lldrawfrustum.cpp
deleted file mode 100644
index 1d583223c8..0000000000
--- a/indra/newview/lldrawfrustum.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/** 
-* @file lldrawfrustum.cpp
-* @brief Implementation of lldrawfrustum
-*
-* $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$
-*/
-
-#include "llviewerprecompiledheaders.h"
-
-#include "lldrawfrustum.h"
-
-#include "llviewercontrol.h"
-
-LLDrawFrustum::LLDrawFrustum()
-    : mContextConeOpacity(0.f)
-{
-    mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha"); // 0.0f
-    mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha"); // 1.f
-    mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime"); // 0.08f
-}
-
-LLDrawFrustum::LLDrawFrustum(LLView *origin)
-    : mContextConeOpacity(0.f)
-{
-    mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
-    mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
-    mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
-    setFrustumOrigin(origin);
-}
-
-void LLDrawFrustum::setFrustumOrigin(LLView *origin)
-{
-    if (origin)
-    {
-        mFrustumOrigin = origin->getHandle();
-    }
-}
-
-void LLDrawFrustum::drawFrustum(const LLRect &derived_local_rect, const LLView *root_view, const LLView *drag_handle, bool has_focus)
-{
-    if (mFrustumOrigin.get())
-    {
-        LLView * frustumOrigin = mFrustumOrigin.get();
-        LLRect origin_rect;
-        frustumOrigin->localRectToOtherView(frustumOrigin->getLocalRect(), &origin_rect, root_view);
-        // draw context cone connecting derived floater (ex: color picker) with view (ex: color swatch) in parent floater
-        if (has_focus && frustumOrigin->isInVisibleChain() && mContextConeOpacity > 0.001f)
-        {
-            gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-            LLGLEnable(GL_CULL_FACE);
-            gGL.begin(LLRender::QUADS);
-            {
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-                gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
-                gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-                gGL.vertex2i(derived_local_rect.mRight, derived_local_rect.mTop);
-                gGL.vertex2i(derived_local_rect.mLeft, derived_local_rect.mTop);
-
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-                gGL.vertex2i(derived_local_rect.mLeft, derived_local_rect.mTop);
-                gGL.vertex2i(derived_local_rect.mLeft, derived_local_rect.mBottom);
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-                gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
-                gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
-
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-                gGL.vertex2i(derived_local_rect.mRight, derived_local_rect.mBottom);
-                gGL.vertex2i(derived_local_rect.mRight, derived_local_rect.mTop);
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-                gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
-                gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
-
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-                gGL.vertex2i(derived_local_rect.mLeft, derived_local_rect.mBottom);
-                gGL.vertex2i(derived_local_rect.mRight, derived_local_rect.mBottom);
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-                gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
-                gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
-            }
-            gGL.end();
-        }
-
-        if (gFocusMgr.childHasMouseCapture(drag_handle))
-        {
-            mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(mContextConeFadeTime));
-        }
-        else
-        {
-            mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(mContextConeFadeTime));
-        }
-    }
-}
-
diff --git a/indra/newview/lldrawfrustum.h b/indra/newview/lldrawfrustum.h
deleted file mode 100644
index f6f62d737c..0000000000
--- a/indra/newview/lldrawfrustum.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/** 
-* @file   lldrawfrustum.h
-* @brief  Header file for lldrawfrustum
-*
-* $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_LLDRAWFRUSTUM_H
-#define LL_LLDRAWFRUSTUM_H
-
-#include "llview.h" 
-
-class LLDrawFrustum
-{
-public:
-    LLDrawFrustum();
-    LLDrawFrustum(LLView *origin);
-protected:
-
-    // Draw's a cone from origin to derived view or floater
-    // @derived_local_rect derived flaoter's local rect
-    // @droot_view usually it is a derived floater
-    // @drag_handle floater's drag handle getDragHandle()
-    void drawFrustum(const LLRect &derived_local_rect, const LLView *root_view, const LLView *drag_handle, bool has_focus);
-
-    void setFrustumOrigin(LLView *origin);
-private:
-
-    LLHandle <LLView>   mFrustumOrigin;
-    F32		            mContextConeOpacity;
-    F32                 mContextConeInAlpha;
-    F32                 mContextConeOutAlpha;
-    F32                 mContextConeFadeTime;
-};
-
-#endif // LL_LLDRAWFRUSTUM_H
-
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index e86c10d00b..33099db1b9 100644
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -81,7 +81,6 @@ LLFloaterAvatarPicker* LLFloaterAvatarPicker::show(select_callback_t callback,
 	floater->mNearMeListComplete = FALSE;
 	floater->mCloseOnSelect = closeOnSelect;
 	floater->mExcludeAgentFromSearchResults = skip_agent;
-    floater->setFrustumOrigin(frustumOrigin);
 	
 	if (!closeOnSelect)
 	{
@@ -92,6 +91,10 @@ LLFloaterAvatarPicker* LLFloaterAvatarPicker::show(select_callback_t callback,
 		floater->getChild<LLButton>("cancel_btn")->setLabel(close_string);
 	}
 
+    if(frustumOrigin)
+    {
+        floater->mFrustumOrigin = frustumOrigin->getHandle();
+    }
 
 	return floater;
 }
@@ -101,9 +104,17 @@ LLFloaterAvatarPicker::LLFloaterAvatarPicker(const LLSD& key)
   : LLFloater(key),
 	mNumResultsReturned(0),
 	mNearMeListComplete(FALSE),
-	mCloseOnSelect(FALSE)
+	mCloseOnSelect(FALSE),
+    mContextConeOpacity	(0.f),
+    mContextConeInAlpha(0.f),
+    mContextConeOutAlpha(0.f),
+    mContextConeFadeTime(0.f)
 {
 	mCommitCallbackRegistrar.add("Refresh.FriendList", boost::bind(&LLFloaterAvatarPicker::populateFriend, this));
+
+    mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
+    mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
+    mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
 }
 
 BOOL LLFloaterAvatarPicker::postBuild()
@@ -348,10 +359,66 @@ void LLFloaterAvatarPicker::populateFriend()
 	friends_scroller->sortByColumnIndex(0, TRUE);
 }
 
+void LLFloaterAvatarPicker::drawFrustum()
+{
+    if(mFrustumOrigin.get())
+    {
+        LLView * frustumOrigin = mFrustumOrigin.get();
+        LLRect origin_rect;
+        frustumOrigin->localRectToOtherView(frustumOrigin->getLocalRect(), &origin_rect, this);
+        // draw context cone connecting color picker with color swatch in parent floater
+        LLRect local_rect = getLocalRect();
+        if (hasFocus() && frustumOrigin->isInVisibleChain() && mContextConeOpacity > 0.001f)
+        {
+            gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+            LLGLEnable(GL_CULL_FACE);
+            gGL.begin(LLRender::QUADS);
+            {
+                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+                gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
+                gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
+                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+                gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+                gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+
+                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+                gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+                gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+                gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
+                gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
+
+                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+                gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+                gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+                gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
+                gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
+
+                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+                gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+                gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+                gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
+                gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
+            }
+            gGL.end();
+        }
+
+        if (gFocusMgr.childHasMouseCapture(getDragHandle()))
+        {
+            mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLSmoothInterpolation::getInterpolant(mContextConeFadeTime));
+        }
+        else
+        {
+            mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(mContextConeFadeTime));
+        }
+    }
+}
+
 void LLFloaterAvatarPicker::draw()
 {
-    LLRect local_rect = getLocalRect();
-    drawFrustum(local_rect, this, getDragHandle(), hasFocus());
+    drawFrustum();
 
 	// sometimes it is hard to determine when Select/Ok button should be disabled (see LLAvatarActions::shareWithAvatars).
 	// lets check this via mOkButtonValidateSignal callback periodically.
diff --git a/indra/newview/llfloateravatarpicker.h b/indra/newview/llfloateravatarpicker.h
index 7d94199786..fbee61b054 100644
--- a/indra/newview/llfloateravatarpicker.h
+++ b/indra/newview/llfloateravatarpicker.h
@@ -28,7 +28,6 @@
 #define LLFLOATERAVATARPICKER_H
 
 #include "llfloater.h"
-#include "lldrawfrustum.h"
 #include "lleventcoro.h"
 #include "llcoros.h"
 
@@ -37,7 +36,7 @@
 class LLAvatarName;
 class LLScrollListCtrl;
 
-class LLFloaterAvatarPicker :public LLFloater, public LLDrawFrustum
+class LLFloaterAvatarPicker :public LLFloater
 {
 public:
 	typedef boost::signals2::signal<bool(const uuid_vec_t&), boost_boolean_combiner> validate_signal_t;
@@ -92,6 +91,7 @@ private:
 	void setAllowMultiple(BOOL allow_multiple);
 	LLScrollListCtrl* getActiveList();
 
+    void drawFrustum();
 	virtual void draw();
 	virtual BOOL handleKeyHere(KEY key, MASK mask);
 
@@ -100,6 +100,11 @@ private:
 	BOOL				mNearMeListComplete;
 	BOOL				mCloseOnSelect;
 	BOOL                mExcludeAgentFromSearchResults;
+    LLHandle <LLView>   mFrustumOrigin;
+    F32		            mContextConeOpacity;
+    F32                 mContextConeInAlpha;
+    F32                 mContextConeOutAlpha;
+    F32                 mContextConeFadeTime;
 
 	validate_signal_t mOkButtonValidateSignal;
 	select_callback_t mSelectionCallback;
diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp
index 9c06f777fb..ec2c9740af 100644
--- a/indra/newview/llfloatercolorpicker.cpp
+++ b/indra/newview/llfloatercolorpicker.cpp
@@ -70,7 +70,6 @@
 
 LLFloaterColorPicker::LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show_apply_immediate )
 	: LLFloater(LLSD()),
-      LLDrawFrustum(swatch),
 	  mComponents			( 3 ),
 	  mMouseDownInLumRegion	( FALSE ),
 	  mMouseDownInHueRegion	( FALSE ),
@@ -101,7 +100,11 @@ LLFloaterColorPicker::LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show
 	  mPaletteRegionHeight	( 40 ),
 	  mSwatch				( swatch ),
 	  mActive				( TRUE ),
-	  mCanApplyImmediately	( show_apply_immediate )
+	  mCanApplyImmediately	( show_apply_immediate ),
+	  mContextConeOpacity	( 0.f ),
+      mContextConeInAlpha   ( 0.f ),
+      mContextConeOutAlpha   ( 0.f ),
+      mContextConeFadeTime   ( 0.f )
 {
 	buildFromFile ( "floater_color_picker.xml");
 
@@ -113,6 +116,10 @@ LLFloaterColorPicker::LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show
 		mApplyImmediateCheck->setEnabled(FALSE);
 		mApplyImmediateCheck->set(FALSE);
 	}
+
+    mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
+    mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
+    mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
 }
 
 LLFloaterColorPicker::~LLFloaterColorPicker()
@@ -478,10 +485,56 @@ BOOL LLFloaterColorPicker::isColorChanged()
 //
 void LLFloaterColorPicker::draw()
 {
+	LLRect swatch_rect;
+	mSwatch->localRectToOtherView(mSwatch->getLocalRect(), &swatch_rect, this);
 	// draw context cone connecting color picker with color swatch in parent floater
 	LLRect local_rect = getLocalRect();
-	drawFrustum(local_rect, this, getDragHandle(), hasFocus());
+	if (hasFocus() && mSwatch->isInVisibleChain() && mContextConeOpacity > 0.001f)
+	{
+		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+		LLGLEnable(GL_CULL_FACE);
+		gGL.begin(LLRender::QUADS);
+		{
+			gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mTop);
+			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mTop);
+			gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+			gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+			gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+
+			gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+			gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+			gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+			gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mBottom);
+			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mTop);
+
+			gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+			gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+			gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+			gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mTop);
+			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mBottom);
+
+			gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+			gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+			gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+			gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mBottom);
+			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mBottom);
+		}
+		gGL.end();
+	}
 
+	if (gFocusMgr.childHasMouseCapture(getDragHandle()))
+	{
+		mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), 
+                                        LLSmoothInterpolation::getInterpolant(mContextConeFadeTime));
+	}
+	else
+	{
+		mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(mContextConeFadeTime));
+	}
 
 	mPipetteBtn->setToggleState(LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance());
 	mApplyImmediateCheck->setEnabled(mActive && mCanApplyImmediately);
diff --git a/indra/newview/llfloatercolorpicker.h b/indra/newview/llfloatercolorpicker.h
index 74b99d5e68..16974a872e 100644
--- a/indra/newview/llfloatercolorpicker.h
+++ b/indra/newview/llfloatercolorpicker.h
@@ -30,7 +30,6 @@
 #include <vector>
 
 #include "llfloater.h"
-#include "lldrawfrustum.h"
 #include "llpointer.h"
 #include "llcolorswatch.h"
 #include "llspinctrl.h"
@@ -42,7 +41,7 @@ class LLCheckBoxCtrl;
 //////////////////////////////////////////////////////////////////////////////
 // floater class
 class LLFloaterColorPicker 
-	: public LLFloater, public LLDrawFrustum
+	: public LLFloater
 {
 	public:
 		LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show_apply_immediate = FALSE);
@@ -64,7 +63,7 @@ class LLFloaterColorPicker
 		void destroyUI ();
 		void cancelSelection ();
 		LLColorSwatchCtrl* getSwatch () { return mSwatch; };
-        void setSwatch(LLColorSwatchCtrl* swatch) { mSwatch = swatch; setFrustumOrigin(mSwatch); }
+		void setSwatch( LLColorSwatchCtrl* swatch) { mSwatch = swatch; }
 
 		// mutator / accessor for original RGB value
 		void setOrigRgb ( F32 origRIn, F32 origGIn, F32 origBIn );
@@ -197,6 +196,12 @@ class LLFloaterColorPicker
 		LLButton* mCancelBtn;
 
 		LLButton* mPipetteBtn;
+
+		F32		  mContextConeOpacity;
+        F32       mContextConeInAlpha;
+        F32       mContextConeOutAlpha;
+        F32       mContextConeFadeTime;
+
 };
 
 #endif // LL_LLFLOATERCOLORPICKER_H
diff --git a/indra/newview/llfloaterexperiencepicker.cpp b/indra/newview/llfloaterexperiencepicker.cpp
index 352b3a4ece..bb54c57baf 100644
--- a/indra/newview/llfloaterexperiencepicker.cpp
+++ b/indra/newview/llfloaterexperiencepicker.cpp
@@ -64,22 +64,88 @@ LLFloaterExperiencePicker* LLFloaterExperiencePicker::show( select_callback_t ca
 		floater->mSearchPanel->filterContent();
 	}
 
-	floater->setFrustumOrigin(frustumOrigin);
+	if(frustumOrigin)
+	{
+		floater->mFrustumOrigin = frustumOrigin->getHandle();
+	}
 
 	return floater;
 }
 
+void LLFloaterExperiencePicker::drawFrustum()
+{
+	if(mFrustumOrigin.get())
+	{
+		LLView * frustumOrigin = mFrustumOrigin.get();
+		LLRect origin_rect;
+		frustumOrigin->localRectToOtherView(frustumOrigin->getLocalRect(), &origin_rect, this);
+		// draw context cone connecting color picker with color swatch in parent floater
+		LLRect local_rect = getLocalRect();
+		if (hasFocus() && frustumOrigin->isInVisibleChain() && mContextConeOpacity > 0.001f)
+		{
+			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+			LLGLEnable(GL_CULL_FACE);
+			gGL.begin(LLRender::QUADS);
+			{
+				gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+				gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
+				gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
+				gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+				gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+				gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+
+				gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+				gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+				gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+				gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+				gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
+				gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
+
+				gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+				gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+				gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+				gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+				gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
+				gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
+
+				gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+				gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+				gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+				gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+				gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
+				gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
+			}
+			gGL.end();
+		}
+
+		if (gFocusMgr.childHasMouseCapture(getDragHandle()))
+		{
+			mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(mContextConeFadeTime));
+		}
+		else
+		{
+			mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(mContextConeFadeTime));
+		}
+	}
+}
+
 void LLFloaterExperiencePicker::draw()
 {
-    LLRect local_rect = getLocalRect();
-    drawFrustum(local_rect, this, getDragHandle(), hasFocus());
+	drawFrustum();
 	LLFloater::draw();
 }
 
 LLFloaterExperiencePicker::LLFloaterExperiencePicker( const LLSD& key )
 	:LLFloater(key)
 	,mSearchPanel(NULL)
+	,mContextConeOpacity(0.f)
+	,mContextConeInAlpha(0.f)
+	,mContextConeOutAlpha(0.f)
+	,mContextConeFadeTime(0.f)
 {
+	mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
+	mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
+	mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
 }
 
 LLFloaterExperiencePicker::~LLFloaterExperiencePicker()
diff --git a/indra/newview/llfloaterexperiencepicker.h b/indra/newview/llfloaterexperiencepicker.h
index 55fc632e18..29054a57db 100644
--- a/indra/newview/llfloaterexperiencepicker.h
+++ b/indra/newview/llfloaterexperiencepicker.h
@@ -28,14 +28,13 @@
 #define LL_LLFLOATEREXPERIENCEPICKER_H
 
 #include "llfloater.h"
-#include "lldrawfrustum.h"
 
 class LLScrollListCtrl;
 class LLLineEditor;
 class LLPanelExperiencePicker;
 
 
-class LLFloaterExperiencePicker : public LLFloater, public LLDrawFrustum
+class LLFloaterExperiencePicker : public LLFloater
 {
 public:
 
@@ -55,6 +54,13 @@ public:
 private:
 
 	LLPanelExperiencePicker* mSearchPanel;
+
+	void drawFrustum();
+	LLHandle <LLView>   mFrustumOrigin;
+	F32		            mContextConeOpacity;
+	F32                 mContextConeInAlpha;
+	F32                 mContextConeOutAlpha;
+	F32                 mContextConeFadeTime;
 };
 
 #endif // LL_LLFLOATEREXPERIENCEPICKER_H
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index f10e0bdd81..8a2fc881a9 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -73,6 +73,10 @@
 
 #include "llavatarappearancedefines.h"
 
+static const F32 CONTEXT_CONE_IN_ALPHA = 0.0f;
+static const F32 CONTEXT_CONE_OUT_ALPHA = 1.f;
+static const F32 CONTEXT_FADE_TIME = 0.08f;
+
 static const S32 LOCAL_TRACKING_ID_COLUMN = 1;
 
 //static const char CURRENT_IMAGE_NAME[] = "Current Texture";
@@ -109,6 +113,7 @@ LLFloaterTexturePicker::LLFloaterTexturePicker(
 	mImmediateFilterPermMask(immediate_filter_perm_mask),
 	mDnDFilterPermMask(dnd_filter_perm_mask),
 	mNonImmediateFilterPermMask(non_immediate_filter_perm_mask),
+	mContextConeOpacity(0.f),
 	mSelectedItemPinned( FALSE ),
 	mCanApply(true),
 	mCanPreview(true),
@@ -122,7 +127,6 @@ LLFloaterTexturePicker::LLFloaterTexturePicker(
 	buildFromFile("floater_texture_ctrl.xml");
 	mCanApplyImmediately = can_apply_immediately;
 	setCanMinimize(FALSE);
-	setFrustumOrigin(mOwner);
 }
 
 LLFloaterTexturePicker::~LLFloaterTexturePicker()
@@ -438,9 +442,59 @@ BOOL LLFloaterTexturePicker::postBuild()
 // virtual
 void LLFloaterTexturePicker::draw()
 {
-	// draw cone of context pointing back to texture swatch	
-    LLRect local_rect = getLocalRect();
-    drawFrustum(local_rect, this, getDragHandle(), hasFocus());
+	if (mOwner)
+	{
+		// draw cone of context pointing back to texture swatch	
+		LLRect owner_rect;
+		mOwner->localRectToOtherView(mOwner->getLocalRect(), &owner_rect, this);
+		LLRect local_rect = getLocalRect();
+		if (gFocusMgr.childHasKeyboardFocus(this) && mOwner->isInVisibleChain() && mContextConeOpacity > 0.001f)
+		{
+			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+			LLGLEnable(GL_CULL_FACE);
+			gGL.begin(LLRender::QUADS);
+			{
+				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
+				gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
+				gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
+				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
+				gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+				gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+
+				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
+				gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+				gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
+				gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
+				gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
+
+				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
+				gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+				gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
+				gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
+				gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
+
+
+				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
+				gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+				gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
+				gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
+				gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
+			}
+			gGL.end();
+		}
+	}
+
+	if (gFocusMgr.childHasMouseCapture(getDragHandle()))
+	{
+		mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLSmoothInterpolation::getInterpolant(CONTEXT_FADE_TIME));
+	}
+	else
+	{
+		mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(CONTEXT_FADE_TIME));
+	}
 
 	updateImageStats();
 
diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h
index c962cf98a2..b2a34a37c4 100644
--- a/indra/newview/lltexturectrl.h
+++ b/indra/newview/lltexturectrl.h
@@ -29,7 +29,6 @@
 #define LL_LLTEXTURECTRL_H
 
 #include "llcoord.h"
-#include "lldrawfrustum.h"
 #include "llfiltereditor.h"
 #include "llfloater.h"
 #include "llfolderview.h"
@@ -250,7 +249,7 @@ typedef boost::function<void()> floater_close_callback;
 typedef boost::function<void(const LLUUID& asset_id)> set_image_asset_id_callback;
 typedef boost::function<void(LLPointer<LLViewerTexture> texture)> set_on_update_image_stats_callback;
 
-class LLFloaterTexturePicker : public LLFloater, public LLDrawFrustum
+class LLFloaterTexturePicker : public LLFloater
 {
 public:
 	LLFloaterTexturePicker(
@@ -292,7 +291,7 @@ public:
 	void			setActive(BOOL active);
 
 	LLView*			getOwner() const { return mOwner; }
-	void			setOwner(LLView* owner) { mOwner = owner; setFrustumOrigin(owner); }
+	void			setOwner(LLView* owner) { mOwner = owner; }
 	void			stopUsingPipette();
 	PermissionMask 	getFilterPermMask();
 
@@ -364,6 +363,7 @@ protected:
 	PermissionMask		mNonImmediateFilterPermMask;
 	BOOL				mCanApplyImmediately;
 	BOOL				mNoCopyTextureSelected;
+	F32					mContextConeOpacity;
 	LLSaveFolderState	mSavedFolderState;
 	BOOL				mSelectedItemPinned;
 
-- 
cgit v1.2.3


From f680e5913ab490a0b2f86ce0ec44ca59d56fb32d Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Mon, 11 Nov 2019 20:38:52 +0200
Subject: SL-6109 Removed LLDrawFrustum and used changes from EEP to prevent
 merge conflicts

---
 indra/llui/llfloater.cpp                    | 69 +++++++++++++++++++++++++++++
 indra/llui/llfloater.h                      | 13 ++++++
 indra/newview/llfloateravatarpicker.cpp     | 55 +----------------------
 indra/newview/llfloatercolorpicker.cpp      | 52 +---------------------
 indra/newview/llfloaterexperiencepicker.cpp | 55 +----------------------
 indra/newview/llsetkeybinddialog.cpp        | 21 +++++++--
 indra/newview/llsetkeybinddialog.h          | 13 +++++-
 indra/newview/lltexturectrl.cpp             | 58 +-----------------------
 8 files changed, 118 insertions(+), 218 deletions(-)

diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index a245dd8f78..d6c2c7bc55 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -37,6 +37,7 @@
 #include "lluictrlfactory.h"
 #include "llbutton.h"
 #include "llcheckboxctrl.h"
+#include "llcriticaldamp.h" // LLSmoothInterpolation
 #include "lldir.h"
 #include "lldraghandle.h"
 #include "llfloaterreg.h"
@@ -64,6 +65,10 @@
 // use this to control "jumping" behavior when Ctrl-Tabbing
 const S32 TABBED_FLOATER_OFFSET = 0;
 
+const F32 LLFloater::CONTEXT_CONE_IN_ALPHA = 0.0f;
+const F32 LLFloater::CONTEXT_CONE_OUT_ALPHA = 1.f;
+const F32 LLFloater::CONTEXT_CONE_FADE_TIME = 0.08f;
+
 namespace LLInitParam
 {
 	void TypeValues<LLFloaterEnums::EOpenPositioning>::declareValues()
@@ -2116,6 +2121,70 @@ void LLFloater::updateTitleButtons()
 	}
 }
 
+void LLFloater::drawConeToOwner(F32 &context_cone_opacity,
+                                F32 max_cone_opacity,
+                                LLView *owner_view,
+                                F32 fade_time,
+                                F32 contex_cone_in_alpha,
+                                F32 contex_cone_out_alpha)
+{
+    if (owner_view
+        && owner_view->isInVisibleChain()
+        && hasFocus()
+        && context_cone_opacity > 0.001f
+        && gFocusMgr.childHasKeyboardFocus(this))
+    {
+        // draw cone of context pointing back to owner (e.x. texture swatch)
+        LLRect owner_rect;
+        owner_view->localRectToOtherView(owner_view->getLocalRect(), &owner_rect, this);
+        LLRect local_rect = getLocalRect();
+
+        gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+        LLGLEnable(GL_CULL_FACE);
+        gGL.begin(LLRender::QUADS);
+        {
+            gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
+            gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
+            gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
+            gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
+            gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+            gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+
+            gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
+            gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+            gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+            gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
+            gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
+            gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
+
+            gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
+            gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+            gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+            gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
+            gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
+            gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
+
+
+            gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
+            gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+            gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+            gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
+            gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
+            gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
+        }
+        gGL.end();
+    }
+
+    if (gFocusMgr.childHasMouseCapture(getDragHandle()))
+    {
+        context_cone_opacity = lerp(context_cone_opacity, max_cone_opacity, LLSmoothInterpolation::getInterpolant(fade_time));
+    }
+    else
+    {
+        context_cone_opacity = lerp(context_cone_opacity, 0.f, LLSmoothInterpolation::getInterpolant(fade_time));
+    }
+}
+
 void LLFloater::buildButtons(const Params& floater_params)
 {
 	static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0);
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 165f67499b..f8c04e8a2f 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -395,6 +395,15 @@ protected:
 
 	virtual void	updateTitleButtons();
 
+	// Draws a cone from this floater to parent floater or view (owner)
+	// Modifies context_cone_opacity (interpolates according to fade time and returns new value)
+	void			drawConeToOwner(F32 &context_cone_opacity,
+									F32 max_cone_opacity,
+									LLView *owner_view,
+									F32 context_fade_time = CONTEXT_CONE_FADE_TIME,
+									F32 contex_cone_in_alpha = CONTEXT_CONE_IN_ALPHA,
+									F32 contex_cone_out_alpha = CONTEXT_CONE_OUT_ALPHA);
+
 private:
 	void			setForeground(BOOL b);	// called only by floaterview
 	void			cleanupHandles(); // remove handles to dead floaters
@@ -424,6 +433,10 @@ private:
 	void			updateTransparency(LLView* view, ETypeTransparency transparency_type);
 
 public:
+	static const F32 CONTEXT_CONE_IN_ALPHA;
+	static const F32 CONTEXT_CONE_OUT_ALPHA;
+	static const F32 CONTEXT_CONE_FADE_TIME;
+
 	// Called when floater is opened, passes mKey
 	// Public so external views or floaters can watch for this floater opening
 	commit_signal_t mOpenSignal;
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index 33099db1b9..ab95bc06b8 100644
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -361,59 +361,8 @@ void LLFloaterAvatarPicker::populateFriend()
 
 void LLFloaterAvatarPicker::drawFrustum()
 {
-    if(mFrustumOrigin.get())
-    {
-        LLView * frustumOrigin = mFrustumOrigin.get();
-        LLRect origin_rect;
-        frustumOrigin->localRectToOtherView(frustumOrigin->getLocalRect(), &origin_rect, this);
-        // draw context cone connecting color picker with color swatch in parent floater
-        LLRect local_rect = getLocalRect();
-        if (hasFocus() && frustumOrigin->isInVisibleChain() && mContextConeOpacity > 0.001f)
-        {
-            gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-            LLGLEnable(GL_CULL_FACE);
-            gGL.begin(LLRender::QUADS);
-            {
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-                gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
-                gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-                gGL.vertex2i(local_rect.mRight, local_rect.mTop);
-                gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
-
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-                gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
-                gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-                gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
-                gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
-
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-                gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
-                gGL.vertex2i(local_rect.mRight, local_rect.mTop);
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-                gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
-                gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
-
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-                gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
-                gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
-                gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-                gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
-                gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
-            }
-            gGL.end();
-        }
-
-        if (gFocusMgr.childHasMouseCapture(getDragHandle()))
-        {
-            mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLSmoothInterpolation::getInterpolant(mContextConeFadeTime));
-        }
-        else
-        {
-            mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(mContextConeFadeTime));
-        }
-    }
+    static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f);
+    drawConeToOwner(mContextConeOpacity, max_opacity, mFrustumOrigin.get(), mContextConeFadeTime, mContextConeInAlpha, mContextConeOutAlpha);
 }
 
 void LLFloaterAvatarPicker::draw()
diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp
index ec2c9740af..1a784223c2 100644
--- a/indra/newview/llfloatercolorpicker.cpp
+++ b/indra/newview/llfloatercolorpicker.cpp
@@ -485,56 +485,8 @@ BOOL LLFloaterColorPicker::isColorChanged()
 //
 void LLFloaterColorPicker::draw()
 {
-	LLRect swatch_rect;
-	mSwatch->localRectToOtherView(mSwatch->getLocalRect(), &swatch_rect, this);
-	// draw context cone connecting color picker with color swatch in parent floater
-	LLRect local_rect = getLocalRect();
-	if (hasFocus() && mSwatch->isInVisibleChain() && mContextConeOpacity > 0.001f)
-	{
-		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-		LLGLEnable(GL_CULL_FACE);
-		gGL.begin(LLRender::QUADS);
-		{
-			gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mTop);
-			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mTop);
-			gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-			gGL.vertex2i(local_rect.mRight, local_rect.mTop);
-			gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
-
-			gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-			gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
-			gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
-			gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mBottom);
-			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mTop);
-
-			gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-			gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
-			gGL.vertex2i(local_rect.mRight, local_rect.mTop);
-			gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mTop);
-			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mBottom);
-
-			gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-			gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
-			gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
-			gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-			gGL.vertex2i(swatch_rect.mRight, swatch_rect.mBottom);
-			gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mBottom);
-		}
-		gGL.end();
-	}
-
-	if (gFocusMgr.childHasMouseCapture(getDragHandle()))
-	{
-		mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), 
-                                        LLSmoothInterpolation::getInterpolant(mContextConeFadeTime));
-	}
-	else
-	{
-		mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(mContextConeFadeTime));
-	}
+	static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f);
+	drawConeToOwner(mContextConeOpacity, max_opacity, mSwatch, mContextConeFadeTime, mContextConeInAlpha, mContextConeOutAlpha);
 
 	mPipetteBtn->setToggleState(LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance());
 	mApplyImmediateCheck->setEnabled(mActive && mCanApplyImmediately);
diff --git a/indra/newview/llfloaterexperiencepicker.cpp b/indra/newview/llfloaterexperiencepicker.cpp
index bb54c57baf..c642da7b83 100644
--- a/indra/newview/llfloaterexperiencepicker.cpp
+++ b/indra/newview/llfloaterexperiencepicker.cpp
@@ -74,59 +74,8 @@ LLFloaterExperiencePicker* LLFloaterExperiencePicker::show( select_callback_t ca
 
 void LLFloaterExperiencePicker::drawFrustum()
 {
-	if(mFrustumOrigin.get())
-	{
-		LLView * frustumOrigin = mFrustumOrigin.get();
-		LLRect origin_rect;
-		frustumOrigin->localRectToOtherView(frustumOrigin->getLocalRect(), &origin_rect, this);
-		// draw context cone connecting color picker with color swatch in parent floater
-		LLRect local_rect = getLocalRect();
-		if (hasFocus() && frustumOrigin->isInVisibleChain() && mContextConeOpacity > 0.001f)
-		{
-			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-			LLGLEnable(GL_CULL_FACE);
-			gGL.begin(LLRender::QUADS);
-			{
-				gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-				gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
-				gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
-				gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-				gGL.vertex2i(local_rect.mRight, local_rect.mTop);
-				gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
-
-				gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-				gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
-				gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
-				gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-				gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
-				gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
-
-				gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-				gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
-				gGL.vertex2i(local_rect.mRight, local_rect.mTop);
-				gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-				gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
-				gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
-
-				gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
-				gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
-				gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
-				gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
-				gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
-				gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
-			}
-			gGL.end();
-		}
-
-		if (gFocusMgr.childHasMouseCapture(getDragHandle()))
-		{
-			mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(mContextConeFadeTime));
-		}
-		else
-		{
-			mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(mContextConeFadeTime));
-		}
-	}
+    static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f);
+    drawConeToOwner(mContextConeOpacity, max_opacity, mFrustumOrigin.get(), mContextConeFadeTime, mContextConeInAlpha, mContextConeOutAlpha);
 }
 
 void LLFloaterExperiencePicker::draw()
diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp
index 8d0d71daaf..4eb76c9d89 100644
--- a/indra/newview/llsetkeybinddialog.cpp
+++ b/indra/newview/llsetkeybinddialog.cpp
@@ -34,6 +34,7 @@
 #include "llfloaterreg.h"
 #include "llfocusmgr.h"
 #include "llkeyconflict.h"
+#include "llviewercontrol.h"
 
 class LLSetKeyBindDialog::Updater : public LLEventTimer
 {
@@ -70,8 +71,15 @@ LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key)
     : LLModalDialog(key),
     pParent(NULL),
     mKeyFilterMask(DEFAULT_KEY_FILTER),
-    pUpdater(NULL)
+    pUpdater(NULL),
+    mContextConeOpacity(0.f),
+    mContextConeInAlpha(0.f),
+    mContextConeOutAlpha(0.f),
+    mContextConeFadeTime(0.f)
 {
+	mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
+	mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
+	mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
 }
 
 LLSetKeyBindDialog::~LLSetKeyBindDialog()
@@ -119,18 +127,23 @@ void LLSetKeyBindDialog::onClose(bool app_quiting)
     LLModalDialog::onClose(app_quiting);
 }
 
+void LLSetKeyBindDialog::drawFrustum()
+{
+    static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f);
+    drawConeToOwner(mContextConeOpacity, max_opacity, mFrustumOrigin.get(), mContextConeFadeTime, mContextConeInAlpha, mContextConeOutAlpha);
+}
+
 //virtual
 void LLSetKeyBindDialog::draw()
 {
-    LLRect local_rect;
-    drawFrustum(local_rect, this, (LLView*)getDragHandle(), hasFocus());
+    drawFrustum();
     LLModalDialog::draw();
 }
 
 void LLSetKeyBindDialog::setParent(LLKeyBindResponderInterface* parent, LLView* frustum_origin, U32 key_mask)
 {
     pParent = parent;
-    setFrustumOrigin(frustum_origin);
+    mFrustumOrigin = frustum_origin->getHandle();
     mKeyFilterMask = key_mask;
 
     std::string input;
diff --git a/indra/newview/llsetkeybinddialog.h b/indra/newview/llsetkeybinddialog.h
index c7b4e3c364..70190230e4 100644
--- a/indra/newview/llsetkeybinddialog.h
+++ b/indra/newview/llsetkeybinddialog.h
@@ -29,7 +29,6 @@
 #define LL_LLSETKEYBINDDIALOG_H
 
 #include "llmodaldialog.h"
-#include "lldrawfrustum.h"
 
 class LLCheckBoxCtrl;
 class LLTextBase;
@@ -54,7 +53,7 @@ public:
     virtual bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes) = 0;
 };
 
-class LLSetKeyBindDialog : public LLModalDialog, public LLDrawFrustum
+class LLSetKeyBindDialog : public LLModalDialog
 {
 public:
     LLSetKeyBindDialog(const LLSD& key);
@@ -90,6 +89,16 @@ private:
     Updater *pUpdater;
 
     static bool sRecordKeys; // for convinience and not to check instance each time
+
+    // drawFrustum
+private:
+    void drawFrustum();
+
+    LLHandle <LLView>   mFrustumOrigin;
+    F32                 mContextConeOpacity;
+    F32                 mContextConeInAlpha;
+    F32                 mContextConeOutAlpha;
+    F32                 mContextConeFadeTime;
 };
 
 
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 8a2fc881a9..6b23052dff 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -73,9 +73,6 @@
 
 #include "llavatarappearancedefines.h"
 
-static const F32 CONTEXT_CONE_IN_ALPHA = 0.0f;
-static const F32 CONTEXT_CONE_OUT_ALPHA = 1.f;
-static const F32 CONTEXT_FADE_TIME = 0.08f;
 
 static const S32 LOCAL_TRACKING_ID_COLUMN = 1;
 
@@ -442,59 +439,8 @@ BOOL LLFloaterTexturePicker::postBuild()
 // virtual
 void LLFloaterTexturePicker::draw()
 {
-	if (mOwner)
-	{
-		// draw cone of context pointing back to texture swatch	
-		LLRect owner_rect;
-		mOwner->localRectToOtherView(mOwner->getLocalRect(), &owner_rect, this);
-		LLRect local_rect = getLocalRect();
-		if (gFocusMgr.childHasKeyboardFocus(this) && mOwner->isInVisibleChain() && mContextConeOpacity > 0.001f)
-		{
-			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-			LLGLEnable(GL_CULL_FACE);
-			gGL.begin(LLRender::QUADS);
-			{
-				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
-				gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
-				gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
-				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
-				gGL.vertex2i(local_rect.mRight, local_rect.mTop);
-				gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
-
-				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
-				gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
-				gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
-				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
-				gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
-				gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
-
-				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
-				gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
-				gGL.vertex2i(local_rect.mRight, local_rect.mTop);
-				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
-				gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
-				gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
-
-
-				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity);
-				gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
-				gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
-				gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity);
-				gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
-				gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
-			}
-			gGL.end();
-		}
-	}
-
-	if (gFocusMgr.childHasMouseCapture(getDragHandle()))
-	{
-		mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLSmoothInterpolation::getInterpolant(CONTEXT_FADE_TIME));
-	}
-	else
-	{
-		mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(CONTEXT_FADE_TIME));
-	}
+    static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f);
+    drawConeToOwner(mContextConeOpacity, max_opacity, mOwner);
 
 	updateImageStats();
 
-- 
cgit v1.2.3


From 0c8f561910cf967d546a7a66ab7e3edcc2ca320e Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Tue, 12 Nov 2019 14:08:01 +0200
Subject: SL-6109 Mouse localization support

---
 indra/newview/llkeyconflict.cpp                | 43 +++++++-------------------
 indra/newview/llviewerinput.cpp                |  6 ++--
 indra/newview/llviewerinput.h                  |  4 +--
 indra/newview/skins/default/xui/en/strings.xml |  9 ++++++
 4 files changed, 27 insertions(+), 35 deletions(-)

diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index 882a1d0caf..a94836c59d 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -36,6 +36,7 @@
 
 #include "llinitparam.h"
 #include "llkeyboard.h"
+#include "lltrans.h"
 #include "llviewercontrol.h"
 #include "llviewerinput.h"
 #include "llviewermenu.h"
@@ -73,7 +74,7 @@ std::string string_from_mask(MASK mask)
     return res;
 }
 
-std::string string_from_mouse(EMouseClickType click)
+std::string string_from_mouse(EMouseClickType click, bool translate)
 {
     std::string res;
     switch (click)
@@ -99,36 +100,12 @@ std::string string_from_mouse(EMouseClickType click)
     default:
         break;
     }
-    return res;
-}
 
-EMouseClickType mouse_from_string(const std::string& input)
-{
-    if (input == "LMB")
-    {
-        return CLICK_LEFT;
-    }
-    if (input == "MMB")
-    {
-        return CLICK_MIDDLE;
-    }
-    if (input == "RMB")
-    {
-        return CLICK_RIGHT;
-    }
-    if (input == "MB4")
-    {
-        return CLICK_BUTTON4;
-    }
-    if (input == "MB5")
-    {
-        return CLICK_BUTTON5;
-    }
-    if (input == "Double LMB")
+    if (translate && !res.empty())
     {
-        return CLICK_DOUBLELEFT;
+        res = LLTrans::getString(res);
     }
-    return CLICK_NONE;
+    return res;
 }
 
 // LLKeyConflictHandler
@@ -266,7 +243,7 @@ std::string LLKeyConflictHandler::getStringFromKeyData(const LLKeyData& keydata)
         result = LLKeyboard::stringFromAccelerator(keydata.mMask);
     }
 
-    result += string_from_mouse(keydata.mMouse);
+    result += string_from_mouse(keydata.mMouse, true);
 
     return result;
 }
@@ -300,7 +277,11 @@ void LLKeyConflictHandler::loadFromSettings(const LLViewerInput::KeyMode& keymod
     {
         KEY key;
         MASK mask;
-        EMouseClickType mouse = it->mouse.isProvided() ? mouse_from_string(it->mouse) : CLICK_NONE;
+        EMouseClickType mouse = CLICK_NONE;
+        if (it->mouse.isProvided())
+        {
+            LLViewerInput::mouseFromString(it->mouse.getValue(), &mouse);
+        }
         if (it->key.getValue().empty())
         {
             key = KEY_NONE;
@@ -528,7 +509,7 @@ void LLKeyConflictHandler::saveToSettings(bool temporary)
                     {
                         // set() because 'optional', for compatibility purposes
                         // just copy old keys.xml and rename to key_bindings.xml, it should work
-                        binding.mouse.set(string_from_mouse(data.mMouse), true);
+                        binding.mouse.set(string_from_mouse(data.mMouse, false), true);
                     }
                     binding.command = iter->first;
                     mode.bindings.add(binding);
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index a267678bb3..0718a27696 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -922,7 +922,8 @@ LLViewerInput::LLViewerInput()
 	}
 }
 
-BOOL LLViewerInput::modeFromString(const std::string& string, S32 *mode) const
+// static
+BOOL LLViewerInput::modeFromString(const std::string& string, S32 *mode)
 {
 	if (string == "FIRST_PERSON")
 	{
@@ -951,7 +952,8 @@ BOOL LLViewerInput::modeFromString(const std::string& string, S32 *mode) const
 	}
 }
 
-BOOL LLViewerInput::mouseFromString(const std::string& string, EMouseClickType *mode) const
+// static
+BOOL LLViewerInput::mouseFromString(const std::string& string, EMouseClickType *mode)
 {
     if (string == "LMB")
     {
diff --git a/indra/newview/llviewerinput.h b/indra/newview/llviewerinput.h
index eff42600fd..1fe55bd585 100644
--- a/indra/newview/llviewerinput.h
+++ b/indra/newview/llviewerinput.h
@@ -112,8 +112,8 @@ public:
 	S32				loadBindingsXML(const std::string& filename);										// returns number bound, 0 on error
 	EKeyboardMode	getMode() const;
 
-	BOOL			modeFromString(const std::string& string, S32 *mode) const;			// False on failure
-	BOOL			mouseFromString(const std::string& string, EMouseClickType *mode) const;// False on failure
+	static BOOL		modeFromString(const std::string& string, S32 *mode);			// False on failure
+	static BOOL		mouseFromString(const std::string& string, EMouseClickType *mode);// False on failure
 
     bool            scanKey(KEY key,
                             BOOL key_down,
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 3a311db25c..0594e18c96 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -4069,6 +4069,15 @@ Try enclosing path to the editor with double quotes.
   <string name="Z">Z</string>
   <!-- Key names end -->
 
+  <!-- Mouse button names (short) begin -->
+  <string name="LMB">LMB</string>
+  <string name="MMB">MMB</string>
+  <string name="RMB">RMB</string>
+  <string name="MB4">MB4</string>
+  <string name="MB5">MB5</string>
+  <string name="Double LMB">Double LMB</string>
+  <!-- Mouse button names end -->
+
   <!-- llviewerwindow -->
   <string name="BeaconParticle">Viewing particle beacons (blue)</string>
   <string name="BeaconPhysical">Viewing physical object beacons (green)</string>
-- 
cgit v1.2.3


From 0bcb065623e7ce6ee956d0bc1c3321c6f0c02af6 Mon Sep 17 00:00:00 2001
From: maxim_productengine <mnikolenko@productengine.com>
Date: Wed, 13 Nov 2019 12:36:51 +0200
Subject: SL-12271 FIXED Notifications are cropped after moving them to the
 'Never show' box

---
 indra/newview/llfloaterpreference.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 05de782838..390dea092d 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -1136,12 +1136,12 @@ void LLFloaterPreference::buildPopupLists()
 						if (it->second.asBoolean())
 						{
 							row["columns"][1]["value"] = formp->getElement(it->first)["ignore"].asString();
+							row["columns"][1]["font"] = "SANSSERIF_SMALL";
+							row["columns"][1]["width"] = 360;
 							break;
 						}
 					}
 				}
-				row["columns"][1]["font"] = "SANSSERIF_SMALL";
-				row["columns"][1]["width"] = 360;
 			}
 			item = disabled_popups.addElement(row);
 		}
-- 
cgit v1.2.3


From 3675c90b2e93be3cf3b8e39f6e32cd39ff30997c Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Fri, 15 Nov 2019 21:12:18 +0200
Subject: SL-11898 Hi-res snapshots do not support UI and HUDs and should not
 show them

---
 indra/newview/llappviewer.cpp            |  1 +
 indra/newview/llfloaterauction.cpp       |  7 +++++--
 indra/newview/llfloaterreporter.cpp      |  2 +-
 indra/newview/llsnapshotlivepreview.cpp  |  2 ++
 indra/newview/llviewermenufile.cpp       |  9 ++++++++-
 indra/newview/llviewermessage.cpp        | 18 ++++++++++++++++--
 indra/newview/llviewerwindow.cpp         | 12 ++++++------
 indra/newview/llviewerwindow.h           |  6 +++---
 indra/newview/llviewerwindowlistener.cpp |  8 ++++++--
 9 files changed, 48 insertions(+), 17 deletions(-)

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index a4703d1eb1..8c56ed3cd1 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -4526,6 +4526,7 @@ void LLAppViewer::saveFinalSnapshot()
 									gViewerWindow->getWindowWidthRaw(),
 									gViewerWindow->getWindowHeightRaw(),
 									FALSE,
+									gSavedSettings.getBOOL("RenderHUDInSnapshot"),
 									TRUE,
 									LLSnapshotModel::SNAPSHOT_TYPE_COLOR,
 									LLSnapshotModel::SNAPSHOT_FORMAT_PNG);
diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp
index 56619e818a..957b2e1e8e 100644
--- a/indra/newview/llfloaterauction.cpp
+++ b/indra/newview/llfloaterauction.cpp
@@ -182,8 +182,11 @@ void LLFloaterAuction::onClickSnapshot(void* data)
 	BOOL success = gViewerWindow->rawSnapshot(raw,
 											  gViewerWindow->getWindowWidthScaled(),
 											  gViewerWindow->getWindowHeightScaled(),
-											  TRUE, FALSE,
-											  FALSE, FALSE);
+											  TRUE,
+											  FALSE,
+											  FALSE, //UI
+											  FALSE, //HUD
+											  FALSE);
 	gForceRenderLandFence = FALSE;
 
 	if (success)
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index 960fd9620d..60cb22c4de 100644
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -936,7 +936,7 @@ void LLFloaterReporter::takeNewSnapshot()
 
 	// Take a screenshot, but don't draw this floater.
 	setVisible(FALSE);
-	if( !gViewerWindow->rawSnapshot(mImageRaw, IMAGE_WIDTH, IMAGE_HEIGHT, TRUE, FALSE, TRUE, FALSE))
+    if (!gViewerWindow->rawSnapshot(mImageRaw, IMAGE_WIDTH, IMAGE_HEIGHT, TRUE, FALSE, gSavedSettings.getBOOL("RenderHUDInSnapshot"), TRUE, FALSE))
 	{
 		LL_WARNS() << "Unable to take screenshot" << LL_ENDL;
 		setVisible(TRUE);
diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp
index 0bba495174..43dc676a63 100644
--- a/indra/newview/llsnapshotlivepreview.cpp
+++ b/indra/newview/llsnapshotlivepreview.cpp
@@ -560,6 +560,7 @@ void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update)
         if(!gViewerWindow->thumbnailSnapshot(raw,
                                          mThumbnailWidth, mThumbnailHeight,
                                          mAllowRenderUI && gSavedSettings.getBOOL("RenderUIInSnapshot"),
+                                         gSavedSettings.getBOOL("RenderHUDInSnapshot"),
                                          FALSE,
                                          mSnapshotBufferType) )
         {
@@ -718,6 +719,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
                 previewp->mKeepAspectRatio,//gSavedSettings.getBOOL("KeepAspectForSnapshot"),
                 previewp->getSnapshotType() == LLSnapshotModel::SNAPSHOT_TEXTURE,
                 previewp->mAllowRenderUI && gSavedSettings.getBOOL("RenderUIInSnapshot"),
+                gSavedSettings.getBOOL("RenderHUDInSnapshot"),
                 FALSE,
                 previewp->mSnapshotBufferType,
                 previewp->getMaxImageSize()))
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index a9a91b158b..687a48e7c1 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -595,10 +595,16 @@ class LLFileTakeSnapshotToDisk : public view_listener_t
 		S32 width = gViewerWindow->getWindowWidthRaw();
 		S32 height = gViewerWindow->getWindowHeightRaw();
 
+		bool render_ui = gSavedSettings.getBOOL("RenderUIInSnapshot");
+		bool render_hud = gSavedSettings.getBOOL("RenderHUDInSnapshot");
+
 		if (gSavedSettings.getBOOL("HighResSnapshot"))
 		{
 			width *= 2;
 			height *= 2;
+			// not compatible wirh UI/HUD
+			render_ui = false;
+			render_hud = false;
 		}
 
 		if (gViewerWindow->rawSnapshot(raw,
@@ -606,7 +612,8 @@ class LLFileTakeSnapshotToDisk : public view_listener_t
 									   height,
 									   TRUE,
 									   FALSE,
-									   gSavedSettings.getBOOL("RenderUIInSnapshot"),
+									   render_ui,
+									   render_hud,
 									   FALSE))
 		{
 			LLPointer<LLImageFormatted> formatted;
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 3998a6af15..1b2aeda720 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -5103,7 +5103,14 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem)
 			std::string snap_filename = gDirUtilp->getLindenUserDir();
 			snap_filename += gDirUtilp->getDirDelimiter();
 			snap_filename += LLStartUp::getScreenHomeFilename();
-			gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, FALSE, LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::SNAPSHOT_FORMAT_PNG);
+            gViewerWindow->saveSnapshot(snap_filename,
+                                        gViewerWindow->getWindowWidthRaw(),
+                                        gViewerWindow->getWindowHeightRaw(),
+                                        FALSE, //UI
+                                        gSavedSettings.getBOOL("RenderHUDInSnapshot"),
+                                        FALSE,
+                                        LLSnapshotModel::SNAPSHOT_TYPE_COLOR,
+                                        LLSnapshotModel::SNAPSHOT_FORMAT_PNG);
 		}
 		
 		if (notificationID == "RegionRestartMinutes" ||
@@ -5201,7 +5208,14 @@ static void process_special_alert_messages(const std::string & message)
 		std::string snap_filename = gDirUtilp->getLindenUserDir();
 		snap_filename += gDirUtilp->getDirDelimiter();
 		snap_filename += LLStartUp::getScreenHomeFilename();
-		gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, FALSE, LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::SNAPSHOT_FORMAT_PNG);
+		gViewerWindow->saveSnapshot(snap_filename,
+                                    gViewerWindow->getWindowWidthRaw(),
+                                    gViewerWindow->getWindowHeightRaw(),
+                                    FALSE,
+                                    gSavedSettings.getBOOL("RenderHUDInSnapshot"),
+                                    FALSE,
+                                    LLSnapshotModel::SNAPSHOT_TYPE_COLOR,
+                                    LLSnapshotModel::SNAPSHOT_FORMAT_PNG);
 	}
 }
 
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index c2a89819a6..6f468270d2 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -4580,12 +4580,12 @@ void LLViewerWindow::movieSize(S32 new_width, S32 new_height)
 	}
 }
 
-BOOL LLViewerWindow::saveSnapshot(const std::string& filepath, S32 image_width, S32 image_height, BOOL show_ui, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type, LLSnapshotModel::ESnapshotFormat format)
+BOOL LLViewerWindow::saveSnapshot(const std::string& filepath, S32 image_width, S32 image_height, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type, LLSnapshotModel::ESnapshotFormat format)
 {
     LL_INFOS() << "Saving snapshot to: " << filepath << LL_ENDL;
 
     LLPointer<LLImageRaw> raw = new LLImageRaw;
-    BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, FALSE, show_ui, do_rebuild);
+    BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, FALSE, show_ui, show_hud, do_rebuild);
 
     if (success)
     {
@@ -4644,16 +4644,16 @@ void LLViewerWindow::resetSnapshotLoc() const
 	gSavedPerAccountSettings.setString("SnapshotBaseDir", std::string());
 }
 
-BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type)
+BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type)
 {
-	return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, do_rebuild, type);
+	return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, show_hud, do_rebuild, type);
 }
 
 // Saves the image from the screen to a raw image
 // Since the required size might be bigger than the available screen, this method rerenders the scene in parts (called subimages) and copy
 // the results over to the final raw image.
 BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, 
-	BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type, S32 max_size)
+    BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type, S32 max_size)
 {
 	if (!raw)
 	{
@@ -4687,7 +4687,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
 		LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI);
 	}
 
-	BOOL hide_hud = !gSavedSettings.getBOOL("RenderHUDInSnapshot") && LLPipeline::sShowHUDAttachments;
+    BOOL hide_hud = !show_hud && LLPipeline::sShowHUDAttachments;
 	if (hide_hud)
 	{
 		LLPipeline::sShowHUDAttachments = FALSE;
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index a6365ab328..1f49c0756c 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -353,10 +353,10 @@ public:
 	// snapshot functionality.
 	// perhaps some of this should move to llfloatershapshot?  -MG
 
-	BOOL			saveSnapshot(const std::string&  filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::ESnapshotFormat format = LLSnapshotModel::SNAPSHOT_FORMAT_BMP);
+	BOOL			saveSnapshot(const std::string&  filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL show_hud = TRUE, BOOL do_rebuild = FALSE, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::ESnapshotFormat format = LLSnapshotModel::SNAPSHOT_FORMAT_BMP);
 	BOOL			rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, BOOL keep_window_aspect = TRUE, BOOL is_texture = FALSE,
-		BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE);
-	BOOL			thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type);
+		BOOL show_ui = TRUE, BOOL show_hud = TRUE, BOOL do_rebuild = FALSE, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE);
+	BOOL			thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type);
 	BOOL			isSnapshotLocSet() const;
 	void			resetSnapshotLoc() const;
 
diff --git a/indra/newview/llviewerwindowlistener.cpp b/indra/newview/llviewerwindowlistener.cpp
index 97b405c1d0..acf25b9792 100644
--- a/indra/newview/llviewerwindowlistener.cpp
+++ b/indra/newview/llviewerwindowlistener.cpp
@@ -50,10 +50,11 @@ LLViewerWindowListener::LLViewerWindowListener(LLViewerWindow* llviewerwindow):
 //  saveSnapshotArgs["width"] = LLSD::Integer();
 //  saveSnapshotArgs["height"] = LLSD::Integer();
 //  saveSnapshotArgs["showui"] = LLSD::Boolean();
+//  saveSnapshotArgs["showhud"] = LLSD::Boolean();
 //  saveSnapshotArgs["rebuild"] = LLSD::Boolean();
 //  saveSnapshotArgs["type"] = LLSD::String();
     add("saveSnapshot",
-        "Save screenshot: [\"filename\"], [\"width\"], [\"height\"], [\"showui\"], [\"rebuild\"], [\"type\"]\n"
+        "Save screenshot: [\"filename\"], [\"width\"], [\"height\"], [\"showui\"], [\"showhud\"], [\"rebuild\"], [\"type\"]\n"
         "type: \"COLOR\", \"DEPTH\"\n"
         "Post on [\"reply\"] an event containing [\"ok\"]",
         &LLViewerWindowListener::saveSnapshot,
@@ -83,6 +84,9 @@ void LLViewerWindowListener::saveSnapshot(const LLSD& event) const
     bool showui = true;
     if (event.has("showui"))
         showui = event["showui"].asBoolean();
+    bool showhud = true;
+    if (event.has("showhud"))
+        showhud = event["showhud"].asBoolean();
     bool rebuild(event["rebuild"]); // defaults to false
     LLSnapshotModel::ESnapshotLayerType type(LLSnapshotModel::SNAPSHOT_TYPE_COLOR);
     if (event.has("type"))
@@ -96,7 +100,7 @@ void LLViewerWindowListener::saveSnapshot(const LLSD& event) const
         }
         type = found->second;
     }
-    bool ok = mViewerWindow->saveSnapshot(event["filename"], width, height, showui, rebuild, type);
+    bool ok = mViewerWindow->saveSnapshot(event["filename"], width, height, showui, showhud, rebuild, type);
     sendReply(LLSDMap("ok", ok), event);
 }
 
-- 
cgit v1.2.3


From 9c1e84908383a188f69346a24aea1c25da1a1be0 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Mon, 18 Nov 2019 20:12:50 +0200
Subject: SL-12305 More missing-file handling

instance().getCurFileName() was returning empty value despite supposedly non-empty filename
---
 indra/llui/lluictrlfactory.h    |  4 ++--
 indra/newview/llchathistory.cpp | 16 ++++++++++++++--
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index 03d946f1b7..f740f14e4d 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -160,8 +160,8 @@ public:
 			LLXMLNodePtr root_node;
 
 			if (!LLUICtrlFactory::getLayeredXMLNode(filename, root_node))
-				{							
-				LL_WARNS() << "Couldn't parse XUI file: " << instance().getCurFileName() << LL_ENDL;
+			{
+                LL_WARNS() << "Couldn't parse XUI from path: " << instance().getCurFileName() << ", from filename: " << filename << LL_ENDL;
 				goto fail;
 			}
 
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 1099d4bc09..722523830b 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -1085,7 +1085,8 @@ LLView* LLChatHistory::getSeparator()
 LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args)
 {
 	LLChatHistoryHeader* header = LLChatHistoryHeader::createInstance(mMessageHeaderFilename);
-	header->setup(chat, style_params, args);
+    if (header)
+        header->setup(chat, style_params, args);
 	return header;
 }
 
@@ -1298,6 +1299,12 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
 			view = getSeparator();
 			p.top_pad = mTopSeparatorPad;
 			p.bottom_pad = mBottomSeparatorPad;
+            if (!view)
+            {
+                // Might be wiser to make this LL_ERRS, getSeparator() should work in case of correct instalation.
+                LL_WARNS() << "Failed to create separator from " << mMessageSeparatorFilename << ": can't append to history" << LL_ENDL;
+                return;
+            }
 		}
 		else
 		{
@@ -1306,7 +1313,12 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
 				p.top_pad = 0;
 			else
 				p.top_pad = mTopHeaderPad;
-			p.bottom_pad = mBottomHeaderPad;
+            p.bottom_pad = mBottomHeaderPad;
+            if (!view)
+            {
+                LL_WARNS() << "Failed to create header from " << mMessageHeaderFilename << ": can't append to history" << LL_ENDL;
+                return;
+            }
 			
 		}
 		p.view = view;
-- 
cgit v1.2.3


From 895c60dfb31b74e45a7ca0427eed707f6b917e20 Mon Sep 17 00:00:00 2001
From: maxim_productengine <mnikolenko@productengine.com>
Date: Tue, 19 Nov 2019 14:21:24 +0200
Subject: =?UTF-8?q?SL-12302=20FIXED=20Information=20about=201024=20x=20102?=
 =?UTF-8?q?4=20texture=20size=20overlaps=20the=20=E2=80=98Default=E2=80=99?=
 =?UTF-8?q?=20button=20in=20the=20Texture=20picker?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../skins/default/xui/en/floater_texture_ctrl.xml       | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
index d122d7491c..2380a23900 100644
--- a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
+++ b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
@@ -93,11 +93,22 @@
      height="14"
      layout="topleft"
      left_delta="12"
+     name="size_lbl"
+     top_pad="4">
+        Size:
+    </text>
+
+    <text
+     type="string"
+     length="1"
+     follows="left|top"
+     height="14"
+     layout="topleft"
+     left_delta="0"
      name="unknown"
      top_pad="4">
-        Size: [DIMENSIONS]
+        [DIMENSIONS]
     </text>
-    
 <!--  middle: inventory mode -->
 
     <button
@@ -139,7 +150,7 @@
      image_unselected="eye_button_inactive.tga"
      layout="topleft"
      left_delta="-80"
-     top_delta="-25"
+     top_delta="-10"
      name="Pipette"
      width="28" />
    <text
-- 
cgit v1.2.3


From dcf8487e4c4aee860bcebca6165ee0a83c1af56d Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Tue, 19 Nov 2019 22:15:41 +0200
Subject: SL-6621 Small rework, should also fix mNumTotalRef related asserts

---
 indra/llcommon/llapr.cpp | 151 ++++++++++++++++++++++++++++-------------------
 indra/llcommon/llapr.h   |   7 +--
 2 files changed, 93 insertions(+), 65 deletions(-)

diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index 29f0c7da9a..984e90f376 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -240,6 +240,64 @@ void _ll_apr_assert_status(apr_status_t status, const char* file, int line)
 	llassert(! _ll_apr_warn_status(status, file, line));
 }
 
+//---------------------------------------------------------------------
+//
+// Scope based pool access
+//
+//---------------------------------------------------------------------
+
+class LLAPRFilePoolScope
+{
+public:
+    LLAPRFilePoolScope() : pPool(NULL), mInitialized(false) {}
+    LLAPRFilePoolScope(LLVolatileAPRPool* poolp) : mInitialized(false)
+    { 
+        setFilePool(poolp);
+    }
+    ~LLAPRFilePoolScope()
+    {
+        reset();
+    }
+    apr_pool_t* getVolatileAPRPool(LLVolatileAPRPool* poolp = NULL)
+    {
+        if (!pPool)
+        {
+            setFilePool(poolp);
+        }
+        if (mInitialized)
+        {
+            // We need one clear per one get
+            // At the moment no need to support multiple calls
+            LL_ERRS() << "LLAPRFilePoolScope is not supposed to be initialized twice" << LL_ENDL;
+        }
+        mInitialized = true;
+        return pPool->getVolatileAPRPool();
+    }
+    void reset()
+    {
+        if (mInitialized)
+        {
+            pPool->clearVolatileAPRPool();
+        }
+    }
+
+private:
+    void setFilePool(LLVolatileAPRPool* poolp = NULL)
+    {
+        if (poolp)
+        {
+            pPool = poolp;
+        }
+        else
+        {
+            pPool = LLAPRFile::sAPRFilePoolp;
+        }
+    }
+
+    LLVolatileAPRPool *pPool;
+    bool mInitialized;
+};
+
 //---------------------------------------------------------------------
 //
 // LLAPRFile functions
@@ -287,9 +345,10 @@ apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLV
 	//check if already open some file
 	llassert_always(!mFile) ;
 	llassert_always(!mCurrentFilePoolp) ;
-	
-	apr_pool_t* apr_pool = pool ? pool->getVolatileAPRPool() : NULL ;
-	s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, getAPRFilePool(apr_pool));
+
+	mCurrentFilePoolp = pool ? pool : sAPRFilePoolp;
+	apr_pool_t* apr_pool = mCurrentFilePoolp->getVolatileAPRPool(); //paired with clear in close()
+	s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, apr_pool);
 
 	if (s != APR_SUCCESS || !mFile)
 	{
@@ -314,14 +373,10 @@ apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLV
 		*sizep = file_size;
 	}
 
-	if(!mCurrentFilePoolp)
+	if (!mFile)
 	{
-		mCurrentFilePoolp = pool ;
-
-		if(!mFile)
-		{
-			close() ;
-		}
+		// It will clean pool
+		close() ;
 	}
 
 	return s ;
@@ -348,17 +403,6 @@ apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOO
 	return s;
 }
 
-apr_pool_t* LLAPRFile::getAPRFilePool(apr_pool_t* pool)
-{	
-	if(!pool)
-	{
-		mCurrentFilePoolp = sAPRFilePoolp ;
-		return mCurrentFilePoolp->getVolatileAPRPool() ;
-	}
-
-	return pool ;
-}
-
 // File I/O
 S32 LLAPRFile::read(void *buf, S32 nbytes)
 {
@@ -415,7 +459,7 @@ S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset)
 //
 
 //static
-apr_status_t LLAPRFile::close(apr_file_t* file_handle, LLVolatileAPRPool* pool) 
+apr_status_t LLAPRFile::close(apr_file_t* file_handle) 
 {
 	apr_status_t ret = APR_SUCCESS ;
 	if(file_handle)
@@ -424,29 +468,23 @@ apr_status_t LLAPRFile::close(apr_file_t* file_handle, LLVolatileAPRPool* pool)
 		file_handle = NULL ;
 	}
 
-	if(pool)
-	{
-		pool->clearVolatileAPRPool() ;
-	}
-
 	return ret ;
 }
 
 //static
-apr_file_t* LLAPRFile::open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags)
+apr_file_t* LLAPRFile::open(const std::string& filename, apr_pool_t* apr_pool, apr_int32_t flags)
 {
 	apr_status_t s;
 	apr_file_t* file_handle ;
 
-	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
 
-	s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool());
+	s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, apr_pool);
 	if (s != APR_SUCCESS || !file_handle)
 	{
 		ll_apr_warn_status(s);
 		LL_WARNS("APR") << " Attempting to open filename: " << filename << LL_ENDL;
 		file_handle = NULL ;
-		close(file_handle, pool) ;
+		close(file_handle) ;
 		return NULL;
 	}
 
@@ -489,8 +527,9 @@ S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset)
 S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)
 {
 	//*****************************************
-	apr_file_t* file_handle = open(filename, pool, APR_READ|APR_BINARY); 
-	//*****************************************	
+	LLAPRFilePoolScope scope(pool);
+	apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), APR_READ|APR_BINARY); 
+	//*****************************************
 	if (!file_handle)
 	{
 		return 0;
@@ -523,7 +562,7 @@ S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nb
 	}
 	
 	//*****************************************
-	close(file_handle, pool) ; 
+	close(file_handle) ; 
 	//*****************************************
 	return (S32)bytes_read;
 }
@@ -537,9 +576,10 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n
 		flags |= APR_APPEND;
 		offset = 0;
 	}
-	
+
 	//*****************************************
-	apr_file_t* file_handle = open(filename, pool, flags);
+	LLAPRFilePoolScope scope(pool);
+	apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), flags);
 	//*****************************************
 	if (!file_handle)
 	{
@@ -573,7 +613,7 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n
 	}
 
 	//*****************************************
-	LLAPRFile::close(file_handle, pool);
+	LLAPRFile::close(file_handle);
 	//*****************************************
 
 	return (S32)bytes_written;
@@ -584,9 +624,8 @@ bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool)
 {
 	apr_status_t s;
 
-	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
-	s = apr_file_remove(filename.c_str(), pool->getVolatileAPRPool());
-	pool->clearVolatileAPRPool() ;
+	LLAPRFilePoolScope scope(pool);
+	s = apr_file_remove(filename.c_str(), scope.getVolatileAPRPool());
 
 	if (s != APR_SUCCESS)
 	{
@@ -602,9 +641,8 @@ bool LLAPRFile::rename(const std::string& filename, const std::string& newname,
 {
 	apr_status_t s;
 
-	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
-	s = apr_file_rename(filename.c_str(), newname.c_str(), pool->getVolatileAPRPool());
-	pool->clearVolatileAPRPool() ;
+	LLAPRFilePoolScope scope(pool);
+	s = apr_file_rename(filename.c_str(), newname.c_str(), scope.getVolatileAPRPool());
 	
 	if (s != APR_SUCCESS)
 	{
@@ -621,18 +659,16 @@ bool LLAPRFile::isExist(const std::string& filename, LLVolatileAPRPool* pool, ap
 	apr_file_t* apr_file;
 	apr_status_t s;
 
-	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
-	s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool());	
+	LLAPRFilePoolScope scope(pool);
+	s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, scope.getVolatileAPRPool());	
 
 	if (s != APR_SUCCESS || !apr_file)
 	{
-		pool->clearVolatileAPRPool() ;
 		return false;
 	}
 	else
 	{
 		apr_file_close(apr_file) ;
-		pool->clearVolatileAPRPool() ;
 		return true;
 	}
 }
@@ -643,14 +679,12 @@ S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool)
 	apr_file_t* apr_file;
 	apr_finfo_t info;
 	apr_status_t s;
-	
-	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
-	s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool->getVolatileAPRPool());
+
+	LLAPRFilePoolScope scope(pool);
+	s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, scope.getVolatileAPRPool());
 	
 	if (s != APR_SUCCESS || !apr_file)
-	{		
-		pool->clearVolatileAPRPool() ;
-		
+	{				
 		return 0;
 	}
 	else
@@ -658,7 +692,6 @@ S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool)
 		apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file);		
 
 		apr_file_close(apr_file) ;
-		pool->clearVolatileAPRPool() ;
 		
 		if (s == APR_SUCCESS)
 		{
@@ -676,9 +709,8 @@ bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool)
 {
 	apr_status_t s;
 
-	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
-	s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool->getVolatileAPRPool());
-	pool->clearVolatileAPRPool() ;
+	LLAPRFilePoolScope scope(pool);
+	s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, scope.getVolatileAPRPool());
 		
 	if (s != APR_SUCCESS)
 	{
@@ -694,9 +726,8 @@ bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool)
 {
 	apr_status_t s;
 
-	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
-	s = apr_file_remove(dirname.c_str(), pool->getVolatileAPRPool());
-	pool->clearVolatileAPRPool() ;
+	LLAPRFilePoolScope scope(pool);
+	s = apr_file_remove(dirname.c_str(), scope.getVolatileAPRPool());
 	
 	if (s != APR_SUCCESS)
 	{
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index da50dda103..0d6637f999 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -180,9 +180,6 @@ public:
 	S32 write(const void* buf, S32 nbytes);
 	
 	apr_file_t* getFileHandle() {return mFile;}	
-
-private:
-	apr_pool_t* getAPRFilePool(apr_pool_t* pool) ;	
 	
 //
 //*******************************************************************************************************************************
@@ -192,8 +189,8 @@ public:
 	static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist.
 
 private:
-	static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags);
-	static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ;
+	static apr_file_t* open(const std::string& filename, apr_pool_t* apr_pool, apr_int32_t flags);
+	static apr_status_t close(apr_file_t* file) ;
 	static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset);
 public:
 	// returns false if failure:
-- 
cgit v1.2.3


From 3152f24dbdce572f6e8fe296ab9ede40e0b175da Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Mon, 25 Nov 2019 23:42:22 +0200
Subject: SL-12358 Preview picker for outfits shouldn't have 'apply now'

---
 indra/newview/lloutfitgallery.cpp                           | 1 +
 indra/newview/skins/default/xui/en/floater_texture_ctrl.xml | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp
index b2b6de94b3..12b46e9bb2 100644
--- a/indra/newview/lloutfitgallery.cpp
+++ b/indra/newview/lloutfitgallery.cpp
@@ -1364,6 +1364,7 @@ void LLOutfitGallery::onSelectPhoto(LLUUID selected_outfit_id)
                 texture_floaterp->setOnFloaterCommitCallback(boost::bind(&LLOutfitGallery::onTexturePickerCommit, this, _1, _2));
                 texture_floaterp->setOnUpdateImageStatsCallback(boost::bind(&LLOutfitGallery::onTexturePickerUpdateImageStats, this, _1));
                 texture_floaterp->setLocalTextureEnabled(FALSE);
+                texture_floaterp->setCanApply(false, true);
             }
 
             floaterp->openFloater();
diff --git a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
index 2380a23900..5d13c5a9b0 100644
--- a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
+++ b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
@@ -159,7 +159,7 @@
      layout="topleft"
      left="8"
      name="preview_disabled"
-     top="266"
+     top="305"
      value="Preview Disabled"
      visible="false"
      width="120" />
-- 
cgit v1.2.3


From 2cffa46defb17feaeff53d83da9c214bb7990b93 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Tue, 26 Nov 2019 16:12:02 +0200
Subject: SL-12358 preview_disabled label had not enough space

---
 indra/newview/skins/default/xui/en/floater_texture_ctrl.xml | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
index 5d13c5a9b0..c2af4f54d0 100644
--- a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
+++ b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
@@ -155,14 +155,15 @@
      width="28" />
    <text
      follows="left|bottom"
-     height="20"
+     height="40"
      layout="topleft"
      left="8"
      name="preview_disabled"
-     top="305"
+     top="285"
      value="Preview Disabled"
+     word_wrap="true"
      visible="false"
-     width="120" />
+     width="87" />
     <filter_editor
      follows="left|top|right"
      height="23"
-- 
cgit v1.2.3


From 191c1791f4f83fee1be6e71aa9e3f246206b2e80 Mon Sep 17 00:00:00 2001
From: maxim_productengine <mnikolenko@productengine.com>
Date: Wed, 27 Nov 2019 15:48:22 +0200
Subject: SL-12356 Recast maturity-level error as a blocking modal

---
 indra/newview/skins/default/xui/en/notifications.xml | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index f2e6848e1a..92711d4397 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -7126,12 +7126,14 @@ You can only claim public land in the Region you&apos;re in.
   </notification>
 
   <notification
-   icon="notify.tga"
+   icon="alertmodal.tga"
    name="RegionTPAccessBlocked"
-   persist="false"
-   type="notify">
+   type="alertmodal">
    <tag>fail</tag>
     The region you're trying to visit contains content exceeding your current preferences.  You can change your preferences using Me &gt; Preferences &gt; General.
+   <usetemplate
+      name="okbutton"
+      yestext="OK"/>
   </notification>
 
   <notification
-- 
cgit v1.2.3


From 95af08341c5b20e7faeb58a4d39fae5d8b25fcee Mon Sep 17 00:00:00 2001
From: AndreyL ProductEngine <alihatskiy@productengine.com>
Date: Thu, 28 Nov 2019 00:51:05 +0200
Subject: Buildfix

---
 indra/llui/llview.cpp                         | 2 +-
 indra/newview/llviewerinput.cpp               | 8 ++++----
 indra/newview/llviewermedia.h                 | 1 +
 indra/newview/llviewerparcelmediaautoplay.cpp | 2 +-
 indra/newview/llviewerwindow.cpp              | 2 +-
 5 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 771d32d2fc..593c8b12fc 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -877,7 +877,7 @@ BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
 		              : LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipDelay" );
 
 		// Even if we don't show tooltips, consume the event, nothing below should show tooltip
-		bool allow_ui_tooltips = LLUI::sSettingGroups["config"]->getBOOL( "BasicUITooltips" );
+		bool allow_ui_tooltips = LLUI::getInstance()->mSettingGroups["config"]->getBOOL("BasicUITooltips");
 		if (allow_ui_tooltips)
 		{
 			LLToolTipMgr::instance().show(LLToolTip::Params()
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index 0718a27696..af0d8cb1fd 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -783,16 +783,16 @@ bool toggle_sit(EKeystate s)
 bool toggle_pause_media(EKeystate s) // analogue of play/pause button in top bar
 {
     if (KEYSTATE_DOWN != s) return true;
-    bool pause = LLViewerMedia::isAnyMediaPlaying();
-    LLViewerMedia::setAllMediaPaused(pause);
+    bool pause = LLViewerMedia::getInstance()->isAnyMediaPlaying();
+    LLViewerMedia::getInstance()->setAllMediaPaused(pause);
     return true;
 }
 
 bool toggle_enable_media(EKeystate s)
 {
     if (KEYSTATE_DOWN != s) return true;
-    bool pause = LLViewerMedia::isAnyMediaPlaying() || LLViewerMedia::isAnyMediaShowing();
-    LLViewerMedia::setAllMediaEnabled(!pause);
+    bool pause = LLViewerMedia::getInstance()->isAnyMediaPlaying() || LLViewerMedia::getInstance()->isAnyMediaShowing();
+    LLViewerMedia::getInstance()->setAllMediaEnabled(!pause);
     return true;
 }
 
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index 2b604d3a7a..a5cde35c88 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -79,6 +79,7 @@ class LLViewerMedia: public LLSingleton<LLViewerMedia>
 
 public:
 	// String to get/set media autoplay in gSavedSettings
+	static const char* AUTO_PLAY_MEDIA_SETTING;
 	static const char* SHOW_MEDIA_ON_OTHERS_SETTING;
 	static const char* SHOW_MEDIA_WITHIN_PARCEL_SETTING;
 	static const char* SHOW_MEDIA_OUTSIDE_PARCEL_SETTING;
diff --git a/indra/newview/llviewerparcelmediaautoplay.cpp b/indra/newview/llviewerparcelmediaautoplay.cpp
index 54d9804b9c..36c7d436f6 100644
--- a/indra/newview/llviewerparcelmediaautoplay.cpp
+++ b/indra/newview/llviewerparcelmediaautoplay.cpp
@@ -169,7 +169,7 @@ void LLViewerParcelMediaAutoPlay::onStartMusicResponse(const LLUUID &region_id,
         // make sure we are still there
         if (parcel->getLocalID() == parcel_id && gAgent.getRegion()->getRegionID() == region_id)
         {
-            LLViewerParcelMedia::play(parcel);
+            LLViewerParcelMedia::getInstance()->play(parcel);
         }
     }
 }
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 7f87836644..9e9c26a20d 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -3017,7 +3017,7 @@ void LLViewerWindow::handleScrollWheel(S32 clicks)
 
 void LLViewerWindow::handleScrollHWheel(S32 clicks)
 {
-    LLUI::resetMouseIdleTimer();
+    LLUI::getInstance()->resetMouseIdleTimer();
 
     LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
     if (mouse_captor)
-- 
cgit v1.2.3


From d0f3186cb847dc7ba623255dda40252f82ea20ce Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Tue, 4 Feb 2020 01:24:43 +0200
Subject: Mac buildfix

---
 indra/newview/llviewerinput.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index af0d8cb1fd..7a2f5ed7b3 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -45,6 +45,7 @@
 #include "llvoavatarself.h"
 #include "llfloatercamera.h"
 #include "llinitparam.h"
+#include "llselectmgr.h"
 
 //
 // Constants
-- 
cgit v1.2.3


From fba4fcabc4aa4ebd2c7e3f2aa1f7e89ada6a8b14 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 31 Mar 2020 20:53:50 +0300
Subject: Pulled in VVM fixes

---
 autobuild.xml | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/autobuild.xml b/autobuild.xml
index 1f1db48bdc..ed32122fd1 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -3138,9 +3138,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>c5ab9d9d7482e48cd76f4bf391900a8c</string>
+              <string>3c55ce969331e49f930f6ea41e9fc55a</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/43369/385585/viewer_manager-2.0.531000-darwin64-531000.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/53898/499539/viewer_manager-2.0.538279-darwin64-538279.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -3162,9 +3162,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>6b10d7407686d9e12e63576256581e3e</string>
+              <string>cb2ecfe986c57cbc1b1bf03037bdc78b</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/43370/385592/viewer_manager-2.0.531000-windows-531000.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/53881/499377/viewer_manager-2.0.538279-windows-538279.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -3175,7 +3175,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <key>source_type</key>
         <string>hg</string>
         <key>version</key>
-        <string>2.0.531000</string>
+        <string>2.0.538279</string>
       </map>
       <key>vlc-bin</key>
       <map>
-- 
cgit v1.2.3


From b4eb46a7ec05b91d58cd32d65733f3cbadea3cea Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 2 Apr 2020 19:40:17 +0300
Subject: SL-12893 Pulled in VVM fix

---
 autobuild.xml | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/autobuild.xml b/autobuild.xml
index ed32122fd1..ee23e67de7 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -3138,9 +3138,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>3c55ce969331e49f930f6ea41e9fc55a</string>
+              <string>6ecb848ec5cc18cd073365ae53501087</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/53898/499539/viewer_manager-2.0.538279-darwin64-538279.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55842/522299/viewer_manager-2.0.539609-darwin64-539609.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -3162,9 +3162,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>cb2ecfe986c57cbc1b1bf03037bdc78b</string>
+              <string>aa7999442058328205f1f7b2f8faeda2</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/53881/499377/viewer_manager-2.0.538279-windows-538279.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55843/522306/viewer_manager-2.0.539609-windows-539609.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -3175,7 +3175,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <key>source_type</key>
         <string>hg</string>
         <key>version</key>
-        <string>2.0.538279</string>
+        <string>2.0.539609</string>
       </map>
       <key>vlc-bin</key>
       <map>
-- 
cgit v1.2.3


From de696d0213b98110f930cae35a8db005e3d1a061 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 2 Apr 2020 22:25:45 +0300
Subject: SL-12893 argparse wasn't reading value right

---
 autobuild.xml | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/autobuild.xml b/autobuild.xml
index ee23e67de7..8a2307f352 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -3138,9 +3138,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>6ecb848ec5cc18cd073365ae53501087</string>
+              <string>5ba21b80695975ab1e1b1c79d0f10c10</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55842/522299/viewer_manager-2.0.539609-darwin64-539609.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55879/522561/viewer_manager-2.0.539630-darwin64-539630.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -3162,9 +3162,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>aa7999442058328205f1f7b2f8faeda2</string>
+              <string>0f788eb745fc062ad737824836e48691</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55843/522306/viewer_manager-2.0.539609-windows-539609.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55880/522567/viewer_manager-2.0.539630-windows-539630.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -3175,7 +3175,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <key>source_type</key>
         <string>hg</string>
         <key>version</key>
-        <string>2.0.539609</string>
+        <string>2.0.539630</string>
       </map>
       <key>vlc-bin</key>
       <map>
-- 
cgit v1.2.3


From 9c31597e5e798d40b00e55187949ef2687917022 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 30 Apr 2020 17:51:46 +0300
Subject: SL-13141 Crashfix contribution

---
 doc/contributions.txt        | 1 +
 indra/newview/llvovolume.cpp | 5 ++++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/doc/contributions.txt b/doc/contributions.txt
index 2153e10888..0f43daa6eb 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -1086,6 +1086,7 @@ Nicky Dasmijn
 	SL-10293
 	SL-11061
     SL-11072
+	SL-13141
 Nicky Perian
 	OPEN-1
 	STORM-1087
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 2ffd462ac3..a6500d1399 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -261,7 +261,10 @@ void LLVOVolume::markDead()
 {
 	if (!mDead)
 	{
-		LLSculptIDSize::instance().rem(getVolume()->getParams().getSculptID());
+        if (getVolume())
+        {
+            LLSculptIDSize::instance().rem(getVolume()->getParams().getSculptID());
+        }
 
 		if(getMDCImplCount() > 0)
 		{
-- 
cgit v1.2.3


From b654330f51dea8d5b6b3afd0440a10b2f623bcdd Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Tue, 24 Mar 2020 20:39:36 +0100
Subject: SL-12896 - BOM texture settings

---
 indra/newview/llviewerobject.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index fe3e4cdd61..8fe5a55a4f 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -4800,7 +4800,7 @@ LLViewerTexture* LLViewerObject::getBakedTextureForMagicId(const LLUUID& id)
 	}
 
 	LLVOAvatar* avatar = getAvatar();
-	if (avatar)
+	if (avatar && isRiggedMesh() && !isHUDAttachment())
 	{
 		LLAvatarAppearanceDefines::EBakedTextureIndex texIndex = LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::assetIdToBakedTextureIndex(id);
 		LLViewerTexture* bakedTexture = avatar->getBakedTexture(texIndex);
-- 
cgit v1.2.3


From 85a03549f13622dac8ae7475256f02b96fd8db29 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Tue, 5 May 2020 12:23:59 -0600
Subject: DRTVWR-510 add code to report Vulkan capability in stats
 (Windows-only)

---
 indra/newview/llviewerstats.cpp | 42 +++++++++++++++++++++++++----------------
 1 file changed, 26 insertions(+), 16 deletions(-)

diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 85d87a43af..eccbefcd3e 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -55,7 +55,6 @@
 #include "llviewerregion.h"
 #include "llvoavatar.h"
 #include "llvoavatarself.h"
-#include "llviewerwindow.h"		// *TODO: remove, only used for width/height
 #include "llworld.h"
 #include "llfeaturemanager.h"
 #include "llviewernetwork.h"
@@ -582,21 +581,32 @@ void send_stats()
 	// If the current revision is recent, ping the previous author before overriding
 	LLSD &misc = body["stats"]["misc"];
 
-	// Screen size so the UI team can figure out how big the widgets
-	// appear and use a "typical" size for end user tests.
-
-	S32 window_width = gViewerWindow->getWindowWidthRaw();
-	S32 window_height = gViewerWindow->getWindowHeightRaw();
-	S32 window_size = (window_width * window_height) / 1024;
-	misc["string_1"] = llformat("%d", window_size);
-	misc["string_2"] = llformat("Texture Time: %.2f, Total Time: %.2f", gTextureTimer.getElapsedTimeF32(), gFrameTimeSeconds.value());
-
-	F32 unbaked_time = LLVOAvatar::sUnbakedTime * 1000.f / gFrameTimeSeconds;
-	misc["int_1"] = LLSD::Integer(unbaked_time); // Steve: 1.22
-	F32 grey_time = LLVOAvatar::sGreyTime * 1000.f / gFrameTimeSeconds;
-	misc["int_2"] = LLSD::Integer(grey_time); // Steve: 1.22
-
-	LL_INFOS() << "Misc Stats: int_1: " << misc["int_1"] << " int_2: " << misc["int_2"] << LL_ENDL;
+#ifdef LL_WINDOWS
+    // Probe for Vulkan capability (Dave Houlton 05/2020)
+    //
+    // Check for presense of a Vulkan loader dll, as a proxy for a Vulkan-capable gpu.
+    // False-positives and false-negatives are possible, but unlikely. We'll get a good
+    // approximation of Vulkan capability within current user systems from this. More
+    // detailed information on versions and extensions can come later.
+    HMODULE vulkanDll = LoadLibraryExA("vulkan-1.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
+    if (NULL == vulkanDll)
+    {
+        misc["string_1"] = llformat("No Vulkan driver detected");
+    }
+    else
+    {
+        misc["string_1"] = llformat("Vulkan driver is detected");
+        FreeLibrary(vulkanDll);
+    }
+#else
+    misc["string_1"] = llformat("Unused");
+#endif // LL_WINDOWS
+
+    misc["string_2"] = llformat("Unused");
+    misc["int_1"] = LLSD::Integer(0);
+    misc["int_2"] = LLSD::Integer(0);
+
+    LL_INFOS() << "Misc Stats: int_1: " << misc["int_1"] << " int_2: " << misc["int_2"] << LL_ENDL;
 	LL_INFOS() << "Misc Stats: string_1: " << misc["string_1"] << " string_2: " << misc["string_2"] << LL_ENDL;
 
 	body["DisplayNamesEnabled"] = gSavedSettings.getBOOL("UseDisplayNames");
-- 
cgit v1.2.3


From c19bb9beee7f3bf2b0936db2b1c078ee38c8cc15 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Wed, 6 May 2020 11:55:02 -0600
Subject: DRTVWR-510 cache vulkan-detect result

---
 indra/newview/llviewerstats.cpp | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index eccbefcd3e..04172adde9 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -588,16 +588,22 @@ void send_stats()
     // False-positives and false-negatives are possible, but unlikely. We'll get a good
     // approximation of Vulkan capability within current user systems from this. More
     // detailed information on versions and extensions can come later.
-    HMODULE vulkanDll = LoadLibraryExA("vulkan-1.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
-    if (NULL == vulkanDll)
-    {
-        misc["string_1"] = llformat("No Vulkan driver detected");
-    }
-    else
+    static bool vulkan_oneshot = false;
+    static bool vulkan_detected = false;
+
+    if (!vulkan_oneshot)
     {
-        misc["string_1"] = llformat("Vulkan driver is detected");
-        FreeLibrary(vulkanDll);
+        HMODULE vulkan_loader = LoadLibraryExA("vulkan-1.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
+        if (NULL != vulkan_loader)
+        {
+            vulkan_detected = true;
+            FreeLibrary(vulkan_loader);
+        }
+        vulkan_oneshot = true;
     }
+
+    misc["string_1"] = vulkan_detected ? llformat("Vulkan driver is detected") : llformat("No Vulkan driver detected");
+
 #else
     misc["string_1"] = llformat("Unused");
 #endif // LL_WINDOWS
-- 
cgit v1.2.3


From 663489493edd722f368007148814e9163668cdd2 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 7 May 2020 21:17:24 +0300
Subject: SL-12970 Fixed char length crash

---
 indra/llrender/llgl.cpp       | 16 ++++++++--------
 indra/newview/llappviewer.cpp |  6 +++---
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 4c56b8eace..81d9c89897 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -585,10 +585,10 @@ bool LLGLManager::initGL()
 
 	// Extract video card strings and convert to upper case to
 	// work around driver-to-driver variation in capitalization.
-	mGLVendor = std::string((const char *)glGetString(GL_VENDOR));
+	mGLVendor = ll_safe_string((const char *)glGetString(GL_VENDOR));
 	LLStringUtil::toUpper(mGLVendor);
 
-	mGLRenderer = std::string((const char *)glGetString(GL_RENDERER));
+	mGLRenderer = ll_safe_string((const char *)glGetString(GL_RENDERER));
 	LLStringUtil::toUpper(mGLRenderer);
 
 	parse_gl_version( &mDriverVersionMajor, 
@@ -887,9 +887,9 @@ void LLGLManager::getGLInfo(LLSD& info)
 	}
 	else
 	{
-		info["GLInfo"]["GLVendor"] = std::string((const char *)glGetString(GL_VENDOR));
-		info["GLInfo"]["GLRenderer"] = std::string((const char *)glGetString(GL_RENDERER));
-		info["GLInfo"]["GLVersion"] = std::string((const char *)glGetString(GL_VERSION));
+		info["GLInfo"]["GLVendor"] = ll_safe_string((const char *)glGetString(GL_VENDOR));
+		info["GLInfo"]["GLRenderer"] = ll_safe_string((const char *)glGetString(GL_RENDERER));
+		info["GLInfo"]["GLVersion"] = ll_safe_string((const char *)glGetString(GL_VERSION));
 	}
 
 #if !LL_MESA_HEADLESS
@@ -939,9 +939,9 @@ void LLGLManager::printGLInfoString()
 	}
 	else
 	{
-		LL_INFOS("RenderInit") << "GL_VENDOR:     " << ((const char *)glGetString(GL_VENDOR)) << LL_ENDL;
-		LL_INFOS("RenderInit") << "GL_RENDERER:   " << ((const char *)glGetString(GL_RENDERER)) << LL_ENDL;
-		LL_INFOS("RenderInit") << "GL_VERSION:    " << ((const char *)glGetString(GL_VERSION)) << LL_ENDL;
+		LL_INFOS("RenderInit") << "GL_VENDOR:     " << ll_safe_string((const char *)glGetString(GL_VENDOR)) << LL_ENDL;
+		LL_INFOS("RenderInit") << "GL_RENDERER:   " << ll_safe_string((const char *)glGetString(GL_RENDERER)) << LL_ENDL;
+		LL_INFOS("RenderInit") << "GL_VERSION:    " << ll_safe_string((const char *)glGetString(GL_VERSION)) << LL_ENDL;
 	}
 
 #if !LL_MESA_HEADLESS
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 13a3f3c1f5..0593ad1003 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3146,8 +3146,8 @@ LLSD LLAppViewer::getViewerInfo() const
 	info["MEMORY_MB"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().valueInUnits<LLUnits::Megabytes>());
 	// Moved hack adjustment to Windows memory size into llsys.cpp
 	info["OS_VERSION"] = LLOSInfo::instance().getOSString();
-	info["GRAPHICS_CARD_VENDOR"] = (const char*)(glGetString(GL_VENDOR));
-	info["GRAPHICS_CARD"] = (const char*)(glGetString(GL_RENDERER));
+	info["GRAPHICS_CARD_VENDOR"] = ll_safe_string((const char*)(glGetString(GL_VENDOR)));
+	info["GRAPHICS_CARD"] = ll_safe_string((const char*)(glGetString(GL_RENDERER)));
 
 #if LL_WINDOWS
 	std::string drvinfo = gDXHardware.getDriverVersionWMI();
@@ -3166,7 +3166,7 @@ LLSD LLAppViewer::getViewerInfo() const
 	}
 #endif
 
-	info["OPENGL_VERSION"] = (const char*)(glGetString(GL_VERSION));
+	info["OPENGL_VERSION"] = ll_safe_string((const char*)(glGetString(GL_VERSION)));
 
     // Settings
 
-- 
cgit v1.2.3


From ebc629ffc45e7d1cf66e3f98ee4ca90dea18af33 Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <andreylproductengine@lindenlab.com>
Date: Thu, 14 May 2020 07:51:08 +0000
Subject: Merged in SL-12090 (pull request #105)

SL-12090 Initialize the joystick only when required

* SL-12090 Initialize the joystick only when required

Approved-by: Andrey Kleshchev
---
 indra/newview/llappviewer.cpp       | 5 ++++-
 indra/newview/llfloaterjoystick.cpp | 5 +++++
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 0593ad1003..5630bb1a3f 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1126,7 +1126,10 @@ bool LLAppViewer::init()
 	gSimLastTime = gRenderStartTime.getElapsedTimeF32();
 	gSimFrames = (F32)gFrameCount;
 
-	LLViewerJoystick::getInstance()->init(false);
+    if (gSavedSettings.getBOOL("JoystickEnabled"))
+    {
+        LLViewerJoystick::getInstance()->init(false);
+    }
 
 	try {
 		initializeSecHandler();
diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp
index ee3d633dd0..2b672bc890 100644
--- a/indra/newview/llfloaterjoystick.cpp
+++ b/indra/newview/llfloaterjoystick.cpp
@@ -61,6 +61,11 @@ static LLTrace::SampleStatHandle<>* sJoystickAxes[6] =
 LLFloaterJoystick::LLFloaterJoystick(const LLSD& data)
 	: LLFloater(data)
 {
+    if (!LLViewerJoystick::getInstance()->isJoystickInitialized())
+    {
+        LLViewerJoystick::getInstance()->init(false);
+    }
+
 	initFromSettings();
 }
 
-- 
cgit v1.2.3


From d9cdef171a4e33da2d24508a222cb2ae0d32610a Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Tue, 19 May 2020 12:10:39 +0300
Subject: SL-12904 Restored the missing code (post-merge)

---
 indra/newview/llviewerinput.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index 7a2f5ed7b3..ad4b9d4215 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -364,6 +364,7 @@ bool camera_spin_around_ccw_sitting( EKeystate s )
 	else
 	{
 		//change camera but do not send keystrokes
+		gAgentCamera.unlockView();
 		gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
 	}
 	return true;
@@ -381,6 +382,7 @@ bool camera_spin_around_cw_sitting( EKeystate s )
 	else
 	{
 		//change camera but do not send keystrokes
+		gAgentCamera.unlockView();
 		gAgentCamera.setOrbitRightKey( get_orbit_rate() );
 	}
 	return true;
-- 
cgit v1.2.3


From 8b8a57a977a407dc1fda052d6a6289b5800f48e8 Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Tue, 19 May 2020 19:56:59 +0300
Subject: SL-12896 BOM texture settings - replaced isRiggedMesh() call with
 faster check

---
 indra/newview/llviewerobject.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 8fe5a55a4f..9c91cde09a 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -4800,7 +4800,9 @@ LLViewerTexture* LLViewerObject::getBakedTextureForMagicId(const LLUUID& id)
 	}
 
 	LLVOAvatar* avatar = getAvatar();
-	if (avatar && isRiggedMesh() && !isHUDAttachment())
+	if (avatar && !isHUDAttachment()
+		&& isMesh()
+		&& getVolume() && getVolume()->getParams().getSculptID().notNull()) // checking for the rigged mesh by params instead of using isRiggedMesh() to avoid false negatives when skin info isn't ready
 	{
 		LLAvatarAppearanceDefines::EBakedTextureIndex texIndex = LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::assetIdToBakedTextureIndex(id);
 		LLViewerTexture* bakedTexture = avatar->getBakedTexture(texIndex);
-- 
cgit v1.2.3


From b86fdf1c316a49bab69d7ef6b3751565bedf8f59 Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Tue, 19 May 2020 22:29:27 +0300
Subject: SL-13273 Updated the SL logo images

---
 .../skins/default/textures/windows/login_sl_logo.png | Bin 21797 -> 5764 bytes
 .../default/textures/windows/login_sl_logo_small.png | Bin 5978 -> 4802 bytes
 2 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/indra/newview/skins/default/textures/windows/login_sl_logo.png b/indra/newview/skins/default/textures/windows/login_sl_logo.png
index 9810d00237..1eede80c83 100644
Binary files a/indra/newview/skins/default/textures/windows/login_sl_logo.png and b/indra/newview/skins/default/textures/windows/login_sl_logo.png differ
diff --git a/indra/newview/skins/default/textures/windows/login_sl_logo_small.png b/indra/newview/skins/default/textures/windows/login_sl_logo_small.png
index 0a245442d5..c5933001f0 100644
Binary files a/indra/newview/skins/default/textures/windows/login_sl_logo_small.png and b/indra/newview/skins/default/textures/windows/login_sl_logo_small.png differ
-- 
cgit v1.2.3


From 882d7eee8091a9aa5557513626a009de99fd7ba4 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 27 May 2020 21:15:15 +0300
Subject: SL-13329 Misalligned checkboxes in inventory filters

---
 .../skins/default/xui/en/floater_inventory_view_finder.xml        | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml
index a8342e723b..d783d1e23c 100644
--- a/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml
+++ b/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml
@@ -2,7 +2,7 @@
 <floater
  legacy_header_height="18"
  can_minimize="false"
- height="488"
+ height="466"
  layout="topleft"
  name="Inventory Finder"
  help_topic="inventory_finder"
@@ -202,7 +202,7 @@
      left="8"
      mouse_opaque="true"
      name="icon_settings"
-     top="262"
+     top="242"
      width="16" />
     <check_box
      height="16"
@@ -220,7 +220,7 @@
      layout="topleft"
      left="8"
      name="All"
-     top="282"
+     top="262"
      width="100" />
     <button
      height="20"
@@ -368,6 +368,6 @@
      layout="topleft"
      name="Close"
      right="-6"
-     top="454"
+     top="434"
      width="76" />
 </floater>
-- 
cgit v1.2.3


From f2d2fb2e28575d870ff07ce463dd30fa9af7f505 Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Wed, 10 Jun 2020 05:07:10 +0300
Subject: SL-13412 Disabled the (default) click to walk in mouselook mode

---
 indra/newview/app_settings/key_bindings.xml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml
index dd74293644..81423c4716 100644
--- a/indra/newview/app_settings/key_bindings.xml
+++ b/indra/newview/app_settings/key_bindings.xml
@@ -33,7 +33,6 @@
     <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
-    <binding key="" mask="NONE" mouse="LMB" command="walk_to"/>
   </first_person>
   <third_person>
     <binding key="A" mask="NONE" command="turn_left"/>
-- 
cgit v1.2.3


From 150af85b01aba24e5b006febe58ff17c72f0366b Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 11 Jun 2020 01:31:43 +0300
Subject: SL-13438 Fixed description

---
 indra/newview/skins/default/xui/en/control_table_contents.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/indra/newview/skins/default/xui/en/control_table_contents.xml b/indra/newview/skins/default/xui/en/control_table_contents.xml
index 7b777befee..f3a34c59eb 100644
--- a/indra/newview/skins/default/xui/en/control_table_contents.xml
+++ b/indra/newview/skins/default/xui/en/control_table_contents.xml
@@ -340,7 +340,7 @@
          font="SansSerif"
          halign="left"
          name="lst_action"
-         value="Camera Spin Over" />
+         value="Camera Spin Over Sitting" />
     </rows>
     <rows
      name="spin_under_sitting"
@@ -350,7 +350,7 @@
          font="SansSerif"
          halign="left"
          name="lst_action"
-         value="Camera Spin Under" />
+         value="Camera Spin Under Sitting" />
     </rows>
     <rows
      name="pan_up"
-- 
cgit v1.2.3


From b1f9de4d377c37d1e97f5ef06cbb438cdc755f6f Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 12 Jun 2020 18:51:13 +0300
Subject: SL-13421 Removed camera control keybindings from mouselook

---
 indra/newview/llfloaterpreference.cpp              | 116 +++-
 indra/newview/llfloaterpreference.h                |   8 +-
 indra/newview/llkeyconflict.cpp                    |  51 +-
 indra/newview/llkeyconflict.h                      |   3 +-
 .../default/xui/en/control_table_contents.xml      | 625 ---------------------
 .../xui/en/control_table_contents_camera.xml       | 240 ++++++++
 .../en/control_table_contents_columns_basic.xml    |  19 +
 .../xui/en/control_table_contents_editing.xml      |  80 +++
 .../xui/en/control_table_contents_media.xml        |  76 +++
 .../xui/en/control_table_contents_movement.xml     | 198 +++++++
 10 files changed, 758 insertions(+), 658 deletions(-)
 delete mode 100644 indra/newview/skins/default/xui/en/control_table_contents.xml
 create mode 100644 indra/newview/skins/default/xui/en/control_table_contents_camera.xml
 create mode 100644 indra/newview/skins/default/xui/en/control_table_contents_columns_basic.xml
 create mode 100644 indra/newview/skins/default/xui/en/control_table_contents_editing.xml
 create mode 100644 indra/newview/skins/default/xui/en/control_table_contents_media.xml
 create mode 100644 indra/newview/skins/default/xui/en/control_table_contents_movement.xml

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index f7e984c14f..66f793a82c 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2649,39 +2649,21 @@ void LLPanelPreferenceControls::regenerateControls()
     populateControlTable();
 }
 
-void LLPanelPreferenceControls::populateControlTable()
+bool LLPanelPreferenceControls::addControlTableColumns(const std::string &filename)
 {
-    pControlsTable->clearRows();
-    pControlsTable->clearColumns();
-
-    std::string filename;
-    switch ((LLKeyConflictHandler::ESourceMode)mEditingMode)
-    {
-    case LLKeyConflictHandler::MODE_THIRD_PERSON:
-    case LLKeyConflictHandler::MODE_FIRST_PERSON:
-    case LLKeyConflictHandler::MODE_EDIT_AVATAR:
-    case LLKeyConflictHandler::MODE_SITTING:
-        filename = "control_table_contents.xml";
-        break;
-    default:
-        // 'saved settings' mode doesn't have UI or actual settings yet
-        LL_INFOS() << "Unimplemented mode" << LL_ENDL;
-        return;
-    }
-
     LLXMLNodePtr xmlNode;
     LLScrollListCtrl::Contents contents;
     if (!LLUICtrlFactory::getLayeredXMLNode(filename, xmlNode))
     {
-    LL_WARNS() << "Failed to load " << filename << LL_ENDL;
-    return;
+        LL_WARNS() << "Failed to load " << filename << LL_ENDL;
+        return false;
     }
     LLXUIParser parser;
     parser.readXUI(xmlNode, contents, filename);
 
     if (!contents.validateBlock())
     {
-        return;
+        return false;
     }
 
     for (LLInitParam::ParamIterator<LLScrollListColumn::Params>::const_iterator col_it = contents.columns.begin();
@@ -2691,6 +2673,26 @@ void LLPanelPreferenceControls::populateControlTable()
         pControlsTable->addColumn(*col_it);
     }
 
+    return true;
+}
+
+bool LLPanelPreferenceControls::addControlTableRows(const std::string &filename)
+{
+    LLXMLNodePtr xmlNode;
+    LLScrollListCtrl::Contents contents;
+    if (!LLUICtrlFactory::getLayeredXMLNode(filename, xmlNode))
+    {
+        LL_WARNS() << "Failed to load " << filename << LL_ENDL;
+        return false;
+    }
+    LLXUIParser parser;
+    parser.readXUI(xmlNode, contents, filename);
+
+    if (!contents.validateBlock())
+    {
+        return false;
+    }
+
     LLScrollListCell::Params cell_params;
     // init basic cell params
     cell_params.font = LLFontGL::getFontSansSerif();
@@ -2706,7 +2708,7 @@ void LLPanelPreferenceControls::populateControlTable()
         std::string control = row_it->value.getValue().asString();
         if (!control.empty() && control != "menu_separator")
         {
-            // At the moment 4 collumns are hardcoded
+            // At the moment viewer is hardcoded to assume that there are 4 collumns
             LLScrollListItem::Params item_params(*row_it);
             bool enabled = mConflictHandler[mEditingMode].canAssignControl(control);
             item_params.enabled.setValue(enabled);
@@ -2723,17 +2725,77 @@ void LLPanelPreferenceControls::populateControlTable()
         }
         else
         {
+            // Separator example:
+            // <rows
+            //  enabled = "false">
+            //  <columns
+            //   type = "icon"
+            //   color = "0 0 0 0.7"
+            //   halign = "center"
+            //   value = "menu_separator" />
+            //</rows>
             pControlsTable->addRow(*row_it, EAddPosition::ADD_BOTTOM);
         }
     }
+    return true;
+}
+
+void LLPanelPreferenceControls::addControlTableSeparator()
+{
+    pControlsTable->addSeparator(EAddPosition::ADD_BOTTOM);
 }
 
-// Just a workaround to not care about first separator before headers (we can start from random header)
-void LLPanelPreferenceControls::addSeparator()
+void LLPanelPreferenceControls::populateControlTable()
 {
-    if (pControlsTable->getItemCount() > 0)
+    pControlsTable->clearRows();
+    pControlsTable->clearColumns();
+
+    // add columns
+    std::string filename;
+    switch ((LLKeyConflictHandler::ESourceMode)mEditingMode)
     {
-        pControlsTable->addSeparator(EAddPosition::ADD_BOTTOM);
+    case LLKeyConflictHandler::MODE_THIRD_PERSON:
+    case LLKeyConflictHandler::MODE_FIRST_PERSON:
+    case LLKeyConflictHandler::MODE_EDIT_AVATAR:
+    case LLKeyConflictHandler::MODE_SITTING:
+        filename = "control_table_contents_columns_basic.xml";
+        break;
+    default:
+        // Either unknown mode or MODE_SAVED_SETTINGS
+        // It doesn't have UI or actual settings yet
+        LL_INFOS() << "Unimplemented mode" << LL_ENDL;
+        return;
+    }
+    addControlTableColumns(filename);
+
+    switch ((LLKeyConflictHandler::ESourceMode)mEditingMode)
+    {
+    case LLKeyConflictHandler::MODE_FIRST_PERSON:
+        addControlTableRows("control_table_contents_movement.xml");
+        addControlTableSeparator();
+        addControlTableRows("control_table_contents_media.xml");
+        break;
+    case LLKeyConflictHandler::MODE_THIRD_PERSON:
+    case LLKeyConflictHandler::MODE_EDIT_AVATAR:
+    case LLKeyConflictHandler::MODE_SITTING:
+        addControlTableRows("control_table_contents_movement.xml");
+        addControlTableSeparator();
+
+        // contains couple 'sitting' options, might be good idea to recheck
+        // those and move to own group with sitting/spinning icon
+        addControlTableRows("control_table_contents_camera.xml"); 
+        addControlTableSeparator();
+
+        // Do we need this outside of MODE_EDIT_AVATAR?
+        addControlTableRows("control_table_contents_editing.xml");
+        addControlTableSeparator();
+
+        addControlTableRows("control_table_contents_media.xml");
+        break;
+    default:
+        // 'saved settings' mode doesn't have UI or actual settings yet
+        LL_INFOS() << "Unimplemented mode" << LL_ENDL;
+        return;
     }
 }
 
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 6c2e655270..ea6e1070cd 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -312,8 +312,14 @@ private:
 	// reloads settings, discards current changes, updates table
 	void regenerateControls();
 
+	// These fuctions do not clean previous content
+	bool addControlTableColumns(const std::string &filename);
+	bool addControlTableRows(const std::string &filename);
+	void addControlTableSeparator();
+
+	// Cleans content and then adds content from xml files according to current mEditingMode
 	void populateControlTable();
-	void addSeparator();
+	// Updates keybindings from storage to table
 	void updateTable();
 
 	LLScrollListCtrl* pControlsTable;
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index a94836c59d..be774e7765 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -160,7 +160,7 @@ bool LLKeyConflictHandler::canAssignControl(const std::string &control_name)
     {
         return iter->second.mAssignable;
     }
-    // If we don't know this control means it wasn't assigned by user yet and thus is editable
+    // If we don't know this control, means it wasn't assigned by user yet and thus is editable
     return true;
 }
 
@@ -195,7 +195,8 @@ bool LLKeyConflictHandler::registerControl(const std::string &control_name, U32
     LLKeyConflict &type_data = mControlsMap[control_name];
     if (!type_data.mAssignable)
     {
-        LL_ERRS() << "Error in code, user or system should not be able to change certain controls" << LL_ENDL;
+        // Example: user tried to assign camera spin to all modes, but first person mode doesn't support it
+        return false;
     }
     LLKeyData data(mouse, key, mask, ignore_mask);
     if (type_data.mKeyBind.getKeyData(index) == data)
@@ -764,8 +765,43 @@ void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode)
 {
     // These controls are meant to cause conflicts when user tries to assign same control somewhere else
     // also this can be used to pre-record controls that should not conflict or to assign conflict groups/masks
-    /*registerTemporaryControl(CONTROL_RESERVED_MENU, CLICK_RIGHT, KEY_NONE, MASK_NONE, 0);
-    registerTemporaryControl(CONTROL_DELETE, CLICK_NONE, KEY_DELETE, MASK_NONE, 0);*/
+
+    if (load_mode == MODE_FIRST_PERSON)
+    {
+        // First person view doesn't support camera controls
+        // Note: might be better idea to just load these from control_table_contents_camera.xml
+        // or to pass from floaterpreferences when it loads said file
+        registerTemporaryControl("look_up");
+        registerTemporaryControl("look_down");
+        registerTemporaryControl("move_forward");
+        registerTemporaryControl("move_backward");
+        registerTemporaryControl("move_forward_fast");
+        registerTemporaryControl("move_backward_fast");
+        registerTemporaryControl("move_forward_sitting");
+        registerTemporaryControl("move_backward_sitting");
+        registerTemporaryControl("spin_over");
+        registerTemporaryControl("spin_under");
+        registerTemporaryControl("spin_over_sitting");
+        registerTemporaryControl("spin_under_sitting");
+        registerTemporaryControl("pan_up");
+        registerTemporaryControl("pan_down");
+        registerTemporaryControl("pan_left");
+        registerTemporaryControl("pan_right");
+        registerTemporaryControl("pan_in");
+        registerTemporaryControl("pan_out");
+        registerTemporaryControl("spin_around_ccw");
+        registerTemporaryControl("spin_around_cw");
+        registerTemporaryControl("spin_around_ccw_sitting");
+        registerTemporaryControl("spin_around_cw_sitting");
+
+        // control_table_contents_editing.xml
+        registerTemporaryControl("edit_avatar_spin_ccw");
+        registerTemporaryControl("edit_avatar_spin_cw");
+        registerTemporaryControl("edit_avatar_spin_over");
+        registerTemporaryControl("edit_avatar_spin_under");
+        registerTemporaryControl("edit_avatar_move_forward");
+        registerTemporaryControl("edit_avatar_move_backward");
+    }
 }
 
 bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, const U32 &conlict_mask)
@@ -817,6 +853,13 @@ void LLKeyConflictHandler::registerTemporaryControl(const std::string &control_n
     type_data->mKeyBind.addKeyData(mouse, key, mask, false);
 }
 
+void LLKeyConflictHandler::registerTemporaryControl(const std::string &control_name)
+{
+    LLKeyConflict *type_data = &mControlsMap[control_name];
+    type_data->mAssignable = false;
+    type_data->mConflictMask = 0;
+}
+
 bool LLKeyConflictHandler::clearUnsavedChanges()
 {
     bool result = false;
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index 84730e4d4f..1bb29bc302 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -125,8 +125,9 @@ private:
     void resetToDefaultAndResolve(const std::string &control_name, bool ignore_conflicts);
     void resetToDefaults(ESourceMode mode);
 
-    // at the moment these kind of control is not savable, but takes part will take part in conflict resolution
+    // at the moment these kind of control is not savable, but takes part in conflict resolution
     void registerTemporaryControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask, U32 conflict_mask);
+    void registerTemporaryControl(const std::string &control_name);
 
     typedef std::map<std::string, LLKeyConflict> control_map_t;
     void loadFromSettings(const LLViewerInput::KeyMode& keymode, control_map_t *destination);
diff --git a/indra/newview/skins/default/xui/en/control_table_contents.xml b/indra/newview/skins/default/xui/en/control_table_contents.xml
deleted file mode 100644
index f3a34c59eb..0000000000
--- a/indra/newview/skins/default/xui/en/control_table_contents.xml
+++ /dev/null
@@ -1,625 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<contents>
-    <columns
-     relative_width="0.34"
-     label="Action"
-     name="lst_action" />
-    <columns
-     relative_width="0.22"
-     label="Primary Control"
-     name="lst_ctrl1" />
-    <columns
-     relative_width="0.22"
-     label="Alternate 1"
-     name="lst_ctrl2" />
-    <columns
-     relative_width="0.22"
-     label="Alternate 2"
-     name="lst_ctrl3" />
-    <rows
-     enabled="false"
-     name="move_actions"
-     value="">
-        <columns
-         type="icontext"
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         label="Move Actions"
-         name="lst_action"
-         value="Move_Walk_Off" />
-    </rows>
-    <rows
-     name="walk_to"
-     value="walk_to">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Walk to location mouse cursor points to"
-         value="Walk to" />
-    </rows>
-    <rows
-     name="teleport_to"
-     value="teleport_to">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Teleport to location mouse cursor points to, but not all locations allow direct teleportation so you might be teleported closer to destination instead"
-         value="Teleport to" />
-    </rows>
-    <rows
-     name="push_forward"
-     value="push_forward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Move Forward" />
-    </rows>
-    <rows
-     name="push_backward"
-     value="push_backward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Move Backward" />
-    </rows>
-    <rows
-     name="turn_left"
-     value="turn_left">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Left" />
-    </rows>
-    <rows
-     name="turn_right"
-     value="turn_right">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Right" />
-    </rows>
-    <rows
-     name="slide_left"
-     value="slide_left">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Strafe left" />
-    </rows>
-    <rows
-     name="slide_right"
-     value="slide_right">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Strafe right" />
-    </rows>
-    <rows
-     name="jump"
-     value="jump">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Jump/Up" />
-    </rows>
-    <rows
-     name="push_down"
-     value="push_down">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Down" />
-    </rows>
-    <rows
-     name="run_forward"
-     value="run_forward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Run Forward" />
-    </rows>
-    <rows
-     name="run_backward"
-     value="run_backward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Run Backward" />
-    </rows>
-    <rows
-     name="run_left"
-     value="run_left">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Run Left" />
-    </rows>
-    <rows
-     name="run_right"
-     value="run_right">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Run Right" />
-    </rows>
-    <rows
-     name="toggle_run"
-     value="toggle_run">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Toggle Run" />
-    </rows>
-    <rows
-     name="toggle_fly"
-     value="toggle_fly">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Fly/Stop flying" />
-    </rows>
-    <rows
-     name="toggle_sit"
-     value="toggle_sit">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Sit/Stand" />
-    </rows>
-    <rows
-     name="stop_moving"
-     value="stop_moving">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Stop Moving" />
-    </rows>
-    <rows
-     enabled="false">
-        <columns
-         type="icon"
-         color="0 0 0 0.7"
-         halign="center"
-         value="menu_separator" />
-    </rows>
-    <rows
-     enabled="false"
-     name="camera_actions"
-     value="">
-        <columns
-         type="icontext"
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         label="Camera"
-         name="lst_action"
-         value="Cam_FreeCam_Off" />
-    </rows>
-    <rows
-     name="look_up"
-     value="look_up">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Look Up" />
-    </rows>
-    <rows
-     name="look_down"
-     value="look_down">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Look Down" />
-    </rows>
-    <rows
-     name="move_forward"
-     value="move_forward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Forward" />
-    </rows>
-    <rows
-     name="move_backward"
-     value="move_backward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Backward" />
-    </rows>
-    <rows
-     name="move_forward_fast"
-     value="move_forward_fast">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Forward Fast" />
-    </rows>
-    <rows
-     name="move_backward_fast"
-     value="move_backward_fast">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Backward Fast" />
-    </rows>
-    <rows
-     name="move_forward_sitting"
-     value="move_forward_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Forward Sitting" />
-    </rows>
-    <rows
-     name="move_backward_sitting"
-     value="move_backward_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Backward Sitting" />
-    </rows>
-    <rows
-     name="spin_over"
-     value="spin_over">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Spin Over" />
-    </rows>
-    <rows
-     name="spin_under"
-     value="spin_under">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Spin Under" />
-    </rows>
-    <rows
-     name="spin_over_sitting"
-     value="spin_over_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Spin Over Sitting" />
-    </rows>
-    <rows
-     name="spin_under_sitting"
-     value="spin_under_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Spin Under Sitting" />
-    </rows>
-    <rows
-     name="pan_up"
-     value="pan_up">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan Up" />
-    </rows>
-    <rows
-     name="pan_down"
-     value="pan_down">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan Down" />
-    </rows>
-    <rows
-     name="pan_left"
-     value="pan_left">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan Left" />
-    </rows>
-    <rows
-     name="pan_right"
-     value="pan_right">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan Right" />
-    </rows>
-    <rows
-     name="pan_in"
-     value="pan_in">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan In" />
-    </rows>
-    <rows
-     name="pan_out"
-     value="pan_out">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan Out" />
-    </rows>
-    <rows
-     name="spin_around_ccw"
-     value="spin_around_ccw">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around counterclockwise"
-         value="Counterclockwise" />
-    </rows>
-    <rows
-     name="spin_around_cw"
-     value="spin_around_cw">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around clockwise"
-         value="Clockwise" />
-    </rows>
-    <rows
-     name="spin_around_ccw_sitting"
-     value="spin_around_ccw_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around counterclockwise sitting"
-         value="Counterclockwise Sitting" />
-    </rows>
-    <rows
-     name="spin_around_cw_sitting"
-     value="spin_around_cw_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around clockwise sitting"
-         value="Clockwise Sitting" />
-    </rows>
-    <rows
-     enabled="false">
-        <columns
-         type="icon"
-         color="0 0 0 0.7"
-         halign="center"
-         value="menu_separator" />
-    </rows>
-    <rows
-     enabled="false"
-     name="editing_actions"
-     value="">
-        <columns
-         type="icontext"
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         label="Editing"
-         name="lst_action"
-         value="Tool_Dozer" />
-    </rows>
-    <rows
-     name="edit_avatar_spin_ccw"
-     value="edit_avatar_spin_ccw">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around avatar counterclockwise"
-         value="Counterclockwise" />
-    </rows>
-    <rows
-     name="edit_avatar_spin_cw"
-     value="edit_avatar_spin_cw">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around avatar clockwise"
-         value="Clockwise" />
-    </rows>
-    <rows
-     name="edit_avatar_spin_over"
-     value="edit_avatar_spin_over">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin over avatar"
-         value="Camera Spin Over" />
-    </rows>
-    <rows
-     name="edit_avatar_spin_under"
-     value="edit_avatar_spin_under">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin under avatar"
-         value="Camera Spin Under" />
-    </rows>
-    <rows
-     name="edit_avatar_move_forward"
-     value="edit_avatar_move_forward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Forward" />
-    </rows>
-    <rows
-     name="edit_avatar_move_backward"
-     value="edit_avatar_move_backward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Backward" />
-    </rows>
-    <rows
-     enabled="false">
-        <columns
-         type="icon"
-         color="0 0 0 0.7"
-         halign="center"
-         value="menu_separator" />
-    </rows>
-    <rows
-     enabled="false"
-     name="media_actions"
-     value="">
-        <columns
-         type="icontext"
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         label="Sound and Media"
-         name="lst_action"
-         value="Audio_Press" />
-    </rows>
-    <rows
-     name="toggle_pause_media"
-     value="toggle_pause_media">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Play/Pause Media" />
-    </rows>
-    <rows
-     name="toggle_enable_media"
-     value="toggle_enable_media">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Play/Stop All Media" />
-    </rows>
-    <rows
-     name="voice_follow_key"
-     value="voice_follow_key">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Voice" />
-    </rows>
-    <rows
-     name="toggle_voice"
-     value="toggle_voice">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Toggle Voice" />
-    </rows>
-    <rows
-     name="start_chat"
-     value="start_chat">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Start Chat" />
-    </rows>
-    <rows
-     name="start_gesture"
-     value="start_gesture">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Start Gesture" />
-    </rows>
-</contents>
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_camera.xml b/indra/newview/skins/default/xui/en/control_table_contents_camera.xml
new file mode 100644
index 0000000000..35cbb02271
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/control_table_contents_camera.xml
@@ -0,0 +1,240 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<contents>
+    <rows
+     enabled="false"
+     name="camera_actions"
+     value="">
+        <columns
+         type="icontext"
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         label="Camera"
+         name="lst_action"
+         value="Cam_FreeCam_Off" />
+    </rows>
+    <rows
+     name="look_up"
+     value="look_up">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Look Up" />
+    </rows>
+    <rows
+     name="look_down"
+     value="look_down">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Look Down" />
+    </rows>
+    <rows
+     name="move_forward"
+     value="move_forward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Forward" />
+    </rows>
+    <rows
+     name="move_backward"
+     value="move_backward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Backward" />
+    </rows>
+    <rows
+     name="move_forward_fast"
+     value="move_forward_fast">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Forward Fast" />
+    </rows>
+    <rows
+     name="move_backward_fast"
+     value="move_backward_fast">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Backward Fast" />
+    </rows>
+    <rows
+     name="move_forward_sitting"
+     value="move_forward_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Forward Sitting" />
+    </rows>
+    <rows
+     name="move_backward_sitting"
+     value="move_backward_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Backward Sitting" />
+    </rows>
+    <rows
+     name="spin_over"
+     value="spin_over">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Spin Over" />
+    </rows>
+    <rows
+     name="spin_under"
+     value="spin_under">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Spin Under" />
+    </rows>
+    <rows
+     name="spin_over_sitting"
+     value="spin_over_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Spin Over Sitting" />
+    </rows>
+    <rows
+     name="spin_under_sitting"
+     value="spin_under_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Spin Under Sitting" />
+    </rows>
+    <rows
+     name="pan_up"
+     value="pan_up">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan Up" />
+    </rows>
+    <rows
+     name="pan_down"
+     value="pan_down">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan Down" />
+    </rows>
+    <rows
+     name="pan_left"
+     value="pan_left">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan Left" />
+    </rows>
+    <rows
+     name="pan_right"
+     value="pan_right">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan Right" />
+    </rows>
+    <rows
+     name="pan_in"
+     value="pan_in">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan In" />
+    </rows>
+    <rows
+     name="pan_out"
+     value="pan_out">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Pan Out" />
+    </rows>
+    <rows
+     name="spin_around_ccw"
+     value="spin_around_ccw">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around counterclockwise"
+         value="Counterclockwise" />
+    </rows>
+    <rows
+     name="spin_around_cw"
+     value="spin_around_cw">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around clockwise"
+         value="Clockwise" />
+    </rows>
+    <rows
+     name="spin_around_ccw_sitting"
+     value="spin_around_ccw_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around counterclockwise sitting"
+         value="Counterclockwise Sitting" />
+    </rows>
+    <rows
+     name="spin_around_cw_sitting"
+     value="spin_around_cw_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around clockwise sitting"
+         value="Clockwise Sitting" />
+    </rows>
+</contents>
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_columns_basic.xml b/indra/newview/skins/default/xui/en/control_table_contents_columns_basic.xml
new file mode 100644
index 0000000000..e707aaf22c
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/control_table_contents_columns_basic.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<contents>
+    <columns
+     relative_width="0.34"
+     label="Action"
+     name="lst_action" />
+    <columns
+     relative_width="0.22"
+     label="Primary Control"
+     name="lst_ctrl1" />
+    <columns
+     relative_width="0.22"
+     label="Alternate 1"
+     name="lst_ctrl2" />
+    <columns
+     relative_width="0.22"
+     label="Alternate 2"
+     name="lst_ctrl3" />
+</contents>
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_editing.xml b/indra/newview/skins/default/xui/en/control_table_contents_editing.xml
new file mode 100644
index 0000000000..2a3314840a
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/control_table_contents_editing.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<contents>
+    <rows
+     enabled="false"
+     name="editing_actions"
+     value="">
+        <columns
+         type="icontext"
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         label="Editing"
+         name="lst_action"
+         value="Tool_Dozer" />
+    </rows>
+    <rows
+     name="edit_avatar_spin_ccw"
+     value="edit_avatar_spin_ccw">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around avatar counterclockwise"
+         value="Counterclockwise" />
+    </rows>
+    <rows
+     name="edit_avatar_spin_cw"
+     value="edit_avatar_spin_cw">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around avatar clockwise"
+         value="Clockwise" />
+    </rows>
+    <rows
+     name="edit_avatar_spin_over"
+     value="edit_avatar_spin_over">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin over avatar"
+         value="Camera Spin Over" />
+    </rows>
+    <rows
+     name="edit_avatar_spin_under"
+     value="edit_avatar_spin_under">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin under avatar"
+         value="Camera Spin Under" />
+    </rows>
+    <rows
+     name="edit_avatar_move_forward"
+     value="edit_avatar_move_forward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Forward" />
+    </rows>
+    <rows
+     name="edit_avatar_move_backward"
+     value="edit_avatar_move_backward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Backward" />
+    </rows>
+</contents>
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_media.xml b/indra/newview/skins/default/xui/en/control_table_contents_media.xml
new file mode 100644
index 0000000000..ce5d3556b6
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/control_table_contents_media.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<contents>
+    <rows
+     enabled="false"
+     name="media_actions"
+     value="">
+        <columns
+         type="icontext"
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         label="Sound and Media"
+         name="lst_action"
+         value="Audio_Press" />
+    </rows>
+    <rows
+     name="toggle_pause_media"
+     value="toggle_pause_media">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Play/Pause Media" />
+    </rows>
+    <rows
+     name="toggle_enable_media"
+     value="toggle_enable_media">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Play/Stop All Media" />
+    </rows>
+    <rows
+     name="voice_follow_key"
+     value="voice_follow_key">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Voice" />
+    </rows>
+    <rows
+     name="toggle_voice"
+     value="toggle_voice">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Toggle Voice" />
+    </rows>
+    <rows
+     name="start_chat"
+     value="start_chat">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Start Chat" />
+    </rows>
+    <rows
+     name="start_gesture"
+     value="start_gesture">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Start Gesture" />
+    </rows>
+</contents>
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_movement.xml b/indra/newview/skins/default/xui/en/control_table_contents_movement.xml
new file mode 100644
index 0000000000..b410d2dc1c
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/control_table_contents_movement.xml
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<contents>
+    <rows
+     enabled="false"
+     name="move_actions"
+     value="">
+        <columns
+         type="icontext"
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         label="Move Actions"
+         name="lst_action"
+         value="Move_Walk_Off" />
+    </rows>
+    <rows
+     name="walk_to"
+     value="walk_to">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Walk to location mouse cursor points to"
+         value="Walk to" />
+    </rows>
+    <rows
+     name="teleport_to"
+     value="teleport_to">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Teleport to location mouse cursor points to, but not all locations allow direct teleportation so you might be teleported closer to destination instead"
+         value="Teleport to" />
+    </rows>
+    <rows
+     name="push_forward"
+     value="push_forward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Move Forward" />
+    </rows>
+    <rows
+     name="push_backward"
+     value="push_backward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Move Backward" />
+    </rows>
+    <rows
+     name="turn_left"
+     value="turn_left">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Left" />
+    </rows>
+    <rows
+     name="turn_right"
+     value="turn_right">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Right" />
+    </rows>
+    <rows
+     name="slide_left"
+     value="slide_left">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Strafe left" />
+    </rows>
+    <rows
+     name="slide_right"
+     value="slide_right">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Strafe right" />
+    </rows>
+    <rows
+     name="jump"
+     value="jump">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Jump/Up" />
+    </rows>
+    <rows
+     name="push_down"
+     value="push_down">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Down" />
+    </rows>
+    <rows
+     name="run_forward"
+     value="run_forward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Run Forward" />
+    </rows>
+    <rows
+     name="run_backward"
+     value="run_backward">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Run Backward" />
+    </rows>
+    <rows
+     name="run_left"
+     value="run_left">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Run Left" />
+    </rows>
+    <rows
+     name="run_right"
+     value="run_right">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Run Right" />
+    </rows>
+    <rows
+     name="toggle_run"
+     value="toggle_run">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Toggle Run" />
+    </rows>
+    <rows
+     name="toggle_fly"
+     value="toggle_fly">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Fly/Stop flying" />
+    </rows>
+    <rows
+     name="toggle_sit"
+     value="toggle_sit">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Sit/Stand" />
+    </rows>
+    <rows
+     name="stop_moving"
+     value="stop_moving">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Stop Moving" />
+    </rows>
+</contents>
-- 
cgit v1.2.3


From ceea2df59634ab09d165943bd7591e7125ee0f80 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 12 Jun 2020 20:09:43 +0300
Subject: SL-13421 Separated some sitting-exclusive controls

---
 indra/newview/llfloaterpreference.cpp              | 28 +++++-----
 indra/newview/llkeyconflict.cpp                    | 23 +++++---
 indra/newview/llkeyconflict.h                      |  2 +-
 .../xui/en/control_table_contents_camera.xml       | 62 ---------------------
 .../en/control_table_contents_camera_sitting.xml   | 65 ++++++++++++++++++++++
 5 files changed, 95 insertions(+), 85 deletions(-)
 create mode 100644 indra/newview/skins/default/xui/en/control_table_contents_camera_sitting.xml

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 66f793a82c..dc5905b6e7 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2768,32 +2768,34 @@ void LLPanelPreferenceControls::populateControlTable()
     }
     addControlTableColumns(filename);
 
-    switch ((LLKeyConflictHandler::ESourceMode)mEditingMode)
+
+    if (mEditingMode == LLKeyConflictHandler::MODE_FIRST_PERSON)
     {
-    case LLKeyConflictHandler::MODE_FIRST_PERSON:
         addControlTableRows("control_table_contents_movement.xml");
         addControlTableSeparator();
         addControlTableRows("control_table_contents_media.xml");
-        break;
-    case LLKeyConflictHandler::MODE_THIRD_PERSON:
-    case LLKeyConflictHandler::MODE_EDIT_AVATAR:
-    case LLKeyConflictHandler::MODE_SITTING:
+    }
+    // MODE_THIRD_PERSON; MODE_EDIT_AVATAR; MODE_SITTING
+    else if (mEditingMode < LLKeyConflictHandler::MODE_SAVED_SETTINGS)
+    {
+        // In case of 'sitting' mode, movements still apply due to vehicles
         addControlTableRows("control_table_contents_movement.xml");
         addControlTableSeparator();
 
-        // contains couple 'sitting' options, might be good idea to recheck
-        // those and move to own group with sitting/spinning icon
-        addControlTableRows("control_table_contents_camera.xml"); 
+        addControlTableRows("control_table_contents_camera.xml");
+        if (mEditingMode == LLKeyConflictHandler::MODE_SITTING)
+        {
+            addControlTableRows("control_table_contents_camera_sitting.xml");
+        }
         addControlTableSeparator();
 
-        // Do we need this outside of MODE_EDIT_AVATAR?
         addControlTableRows("control_table_contents_editing.xml");
         addControlTableSeparator();
 
         addControlTableRows("control_table_contents_media.xml");
-        break;
-    default:
-        // 'saved settings' mode doesn't have UI or actual settings yet
+    }
+    else
+    {
         LL_INFOS() << "Unimplemented mode" << LL_ENDL;
         return;
     }
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index be774e7765..e44f79000e 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -294,8 +294,9 @@ void LLKeyConflictHandler::loadFromSettings(const LLViewerInput::KeyMode& keymod
         LLKeyboard::maskFromString(it->mask, &mask);
         // Note: it->command is also the name of UI element, howhever xml we are loading from
         // might not know all the commands, so UI will have to know what to fill by its own
+        // Assumes U32_MAX conflict mask, and is assignable by default,
+        // but assignability might have been overriden by generatePlaceholders.
         LLKeyConflict &type_data = (*destination)[it->command];
-        type_data.mAssignable = true;
         type_data.mKeyBind.addKeyData(mouse, key, mask, true);
     }
 }
@@ -777,12 +778,8 @@ void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode)
         registerTemporaryControl("move_backward");
         registerTemporaryControl("move_forward_fast");
         registerTemporaryControl("move_backward_fast");
-        registerTemporaryControl("move_forward_sitting");
-        registerTemporaryControl("move_backward_sitting");
         registerTemporaryControl("spin_over");
         registerTemporaryControl("spin_under");
-        registerTemporaryControl("spin_over_sitting");
-        registerTemporaryControl("spin_under_sitting");
         registerTemporaryControl("pan_up");
         registerTemporaryControl("pan_down");
         registerTemporaryControl("pan_left");
@@ -791,8 +788,6 @@ void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode)
         registerTemporaryControl("pan_out");
         registerTemporaryControl("spin_around_ccw");
         registerTemporaryControl("spin_around_cw");
-        registerTemporaryControl("spin_around_ccw_sitting");
-        registerTemporaryControl("spin_around_cw_sitting");
 
         // control_table_contents_editing.xml
         registerTemporaryControl("edit_avatar_spin_ccw");
@@ -802,6 +797,16 @@ void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode)
         registerTemporaryControl("edit_avatar_move_forward");
         registerTemporaryControl("edit_avatar_move_backward");
     }
+
+    if (load_mode != MODE_SITTING)
+    {
+        registerTemporaryControl("move_forward_sitting");
+        registerTemporaryControl("move_backward_sitting");
+        registerTemporaryControl("spin_over_sitting");
+        registerTemporaryControl("spin_under_sitting");
+        registerTemporaryControl("spin_around_ccw_sitting");
+        registerTemporaryControl("spin_around_cw_sitting");
+    }
 }
 
 bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, const U32 &conlict_mask)
@@ -853,11 +858,11 @@ void LLKeyConflictHandler::registerTemporaryControl(const std::string &control_n
     type_data->mKeyBind.addKeyData(mouse, key, mask, false);
 }
 
-void LLKeyConflictHandler::registerTemporaryControl(const std::string &control_name)
+void LLKeyConflictHandler::registerTemporaryControl(const std::string &control_name, U32 conflict_mask)
 {
     LLKeyConflict *type_data = &mControlsMap[control_name];
     type_data->mAssignable = false;
-    type_data->mConflictMask = 0;
+    type_data->mConflictMask = conflict_mask;
 }
 
 bool LLKeyConflictHandler::clearUnsavedChanges()
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index 1bb29bc302..73d59cc217 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -127,7 +127,7 @@ private:
 
     // at the moment these kind of control is not savable, but takes part in conflict resolution
     void registerTemporaryControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask, U32 conflict_mask);
-    void registerTemporaryControl(const std::string &control_name);
+    void registerTemporaryControl(const std::string &control_name, U32 conflict_mask = 0);
 
     typedef std::map<std::string, LLKeyConflict> control_map_t;
     void loadFromSettings(const LLViewerInput::KeyMode& keymode, control_map_t *destination);
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_camera.xml b/indra/newview/skins/default/xui/en/control_table_contents_camera.xml
index 35cbb02271..aba81e3134 100644
--- a/indra/newview/skins/default/xui/en/control_table_contents_camera.xml
+++ b/indra/newview/skins/default/xui/en/control_table_contents_camera.xml
@@ -73,26 +73,6 @@
          name="lst_action"
          value="Camera Backward Fast" />
     </rows>
-    <rows
-     name="move_forward_sitting"
-     value="move_forward_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Forward Sitting" />
-    </rows>
-    <rows
-     name="move_backward_sitting"
-     value="move_backward_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Backward Sitting" />
-    </rows>
     <rows
      name="spin_over"
      value="spin_over">
@@ -113,26 +93,6 @@
          name="lst_action"
          value="Camera Spin Under" />
     </rows>
-    <rows
-     name="spin_over_sitting"
-     value="spin_over_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Spin Over Sitting" />
-    </rows>
-    <rows
-     name="spin_under_sitting"
-     value="spin_under_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Spin Under Sitting" />
-    </rows>
     <rows
      name="pan_up"
      value="pan_up">
@@ -215,26 +175,4 @@
          tool_tip="Camera spin around clockwise"
          value="Clockwise" />
     </rows>
-    <rows
-     name="spin_around_ccw_sitting"
-     value="spin_around_ccw_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around counterclockwise sitting"
-         value="Counterclockwise Sitting" />
-    </rows>
-    <rows
-     name="spin_around_cw_sitting"
-     value="spin_around_cw_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around clockwise sitting"
-         value="Clockwise Sitting" />
-    </rows>
 </contents>
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_camera_sitting.xml b/indra/newview/skins/default/xui/en/control_table_contents_camera_sitting.xml
new file mode 100644
index 0000000000..9334c6e179
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/control_table_contents_camera_sitting.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<contents>
+    <rows
+     name="move_forward_sitting"
+     value="move_forward_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Forward Sitting" />
+    </rows>
+    <rows
+     name="move_backward_sitting"
+     value="move_backward_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Backward Sitting" />
+    </rows>
+    <rows
+     name="spin_over_sitting"
+     value="spin_over_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Spin Over Sitting" />
+    </rows>
+    <rows
+     name="spin_under_sitting"
+     value="spin_under_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         value="Camera Spin Under Sitting" />
+    </rows>
+    <rows
+     name="spin_around_ccw_sitting"
+     value="spin_around_ccw_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around counterclockwise sitting"
+         value="Counterclockwise Sitting" />
+    </rows>
+    <rows
+     name="spin_around_cw_sitting"
+     value="spin_around_cw_sitting">
+        <columns
+         column="lst_action"
+         font="SansSerif"
+         halign="left"
+         name="lst_action"
+         tool_tip="Camera spin around clockwise sitting"
+         value="Clockwise Sitting" />
+    </rows>
+</contents>
-- 
cgit v1.2.3


From d07ef7df92cbc9c2fb16dcd0ddd0322665d440eb Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Mon, 15 Jun 2020 18:13:46 +0300
Subject: SL-13418 Added converter from old mouse binding settings to new ones

---
 indra/llcommon/llkeybind.h                  |  2 +-
 indra/newview/app_settings/key_bindings.xml |  1 -
 indra/newview/llappviewer.cpp               | 99 +++++++++++++++++++++++++++++
 indra/newview/llkeyconflict.cpp             | 67 ++++++++++++++++++-
 indra/newview/llkeyconflict.h               | 16 +++++
 5 files changed, 182 insertions(+), 3 deletions(-)

diff --git a/indra/llcommon/llkeybind.h b/indra/llcommon/llkeybind.h
index ad0ebec67c..c6b4bd970f 100644
--- a/indra/llcommon/llkeybind.h
+++ b/indra/llcommon/llkeybind.h
@@ -53,7 +53,7 @@ public:
     EMouseClickType mMouse;
     KEY mKey;
     MASK mMask;
-    // Either to expect exact match or ignore not expected masks
+    // Either to expect exact match or ignore not expected masks as long as expected mask-bit is present
     bool mIgnoreMasks; 
 };
 
diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml
index 81423c4716..4f6deb1f98 100644
--- a/indra/newview/app_settings/key_bindings.xml
+++ b/indra/newview/app_settings/key_bindings.xml
@@ -224,7 +224,6 @@
     <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
 
     <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
-    <binding key="" mask="NONE" mouse="LMB" command="walk_to"/>
   </sitting>
   <edit_avatar>
     <!--Avatar editing camera controls-->
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 5630bb1a3f..775b6db94b 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -49,6 +49,7 @@
 #include "llwindow.h"
 #include "llviewerstats.h"
 #include "llviewerstatsrecorder.h"
+#include "llkeyconflict.h" // for legacy keybinding support, remove later
 #include "llmarketplacefunctions.h"
 #include "llmarketplacenotifications.h"
 #include "llmd5.h"
@@ -1004,6 +1005,104 @@ bool LLAppViewer::init()
 
 	// Load User's bindings
 	std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml");
+#if 1
+    // Legacy support
+    // Remove #if-#endif section half a year after DRTVWR-501 releases.
+    // Mouse actions are part of keybinding file since DRTVWR-501 instead of being stored in
+    // settings.xml. To support legacy viewers that were storing in  settings.xml we need to
+    // transfer old variables to new format.
+    // Also part of backward compatibility is present in LLKeyConflictHandler to modify
+    // legacy variables on changes in new system (to make sure we won't enforce
+    // legacy values again if user dropped to defaults in new system)
+    if (mIsFirstRun
+        && !gDirUtilp->fileExists(key_bindings_file)) // if file is missing, assume that there were no changes by user yet
+    {
+        // copy mouse actions and voice key changes to new file
+        LL_INFOS("InitInfo") << "Converting legacy mouse bindings to new format" << LL_ENDL;
+        // Load settings from file
+        LLKeyConflictHandler third_person_view(LLKeyConflictHandler::MODE_THIRD_PERSON);
+
+        // Since we are only modifying keybindings if personal file doesn't exist yet,
+        // it should be safe to just overwrite the value
+        // If key is already in use somewhere by default, LLKeyConflictHandler should resolve it.
+        BOOL value = gSavedSettings.getBOOL("DoubleClickAutoPilot");
+        third_person_view.registerControl("walk_to",
+                                          0,
+                                          value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE,
+                                          KEY_NONE,
+                                          MASK_NONE,
+                                          value);
+
+        U32 index = value ? 1 : 0; // we can store multiple combinations per action, so if first is in use by doubleclick, go to second
+        value = gSavedSettings.getBOOL("ClickToWalk");
+        third_person_view.registerControl("walk_to",
+                                          index,
+                                          value ? EMouseClickType::CLICK_LEFT : EMouseClickType::CLICK_NONE,
+                                          KEY_NONE,
+                                          MASK_NONE,
+                                          value);
+
+        value = gSavedSettings.getBOOL("DoubleClickTeleport");
+        third_person_view.registerControl("teleport_to",
+                                          0,
+                                          value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE,
+                                          KEY_NONE,
+                                          MASK_NONE,
+                                          value);
+
+        std::string key_string = gSavedSettings.getString("PushToTalkButton");
+        EMouseClickType mouse = EMouseClickType::CLICK_NONE;
+        KEY key = KEY_NONE;
+        if (key_string == "MiddleMouse")
+        {
+            mouse = EMouseClickType::CLICK_MIDDLE;
+        }
+        else if (key_string == "MouseButton4")
+        {
+            mouse = EMouseClickType::CLICK_BUTTON4;
+        }
+        else if (key_string == "MouseButton5")
+        {
+            mouse = EMouseClickType::CLICK_BUTTON5;
+        }
+        else
+        {
+            LLKeyboard::keyFromString(key_string, &key);
+        }
+
+        value = gSavedSettings.getBOOL("PushToTalkToggle");
+        std::string control_name = value ? "toggle_voice" : "voice_follow_key";
+        third_person_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true);
+
+        if (third_person_view.hasUnsavedChanges())
+        {
+            // calls loadBindingsXML()
+            third_person_view.saveToSettings();
+        }
+
+        // in case of voice we need to repeat this in other modes (teleports and
+        // autopilot are not entirely practical when sitting or editing)
+
+        for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
+        {
+            if (i != LLKeyConflictHandler::MODE_THIRD_PERSON)
+            {
+                LLKeyConflictHandler handler((LLKeyConflictHandler::ESourceMode)i);
+
+                handler.registerControl(control_name, 0, mouse, key, MASK_NONE, true);
+
+                if (handler.hasUnsavedChanges())
+                {
+                    // calls loadBindingsXML()
+                    handler.saveToSettings();
+                }
+            }
+        }
+    }
+    // since something might have gone wrong or there might have been nothing to save
+    // (and because otherwise following code will have to be encased in else{}),
+    // load everything one last time
+#endif
 	if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file))
 	{
 		// Failed to load custom bindings, try default ones
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index e44f79000e..5f966624ca 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -427,7 +427,7 @@ void LLKeyConflictHandler::saveToSettings(bool temporary)
             else if (!key.mKeyBind.empty())
             {
                 // Note: this is currently not in use, might be better for load mechanics to ask for and retain control group
-                // otherwise settings loaded from other control groups will end in this one
+                // otherwise settings loaded from other control groups will end in gSavedSettings
                 LL_INFOS() << "Creating new keybinding " << iter->first << LL_ENDL;
                 gSavedSettings.declareLLSD(iter->first, key.mKeyBind.asLLSD(), "comment", LLControlVariable::PERSIST_ALWAYS);
             }
@@ -598,6 +598,71 @@ void LLKeyConflictHandler::saveToSettings(bool temporary)
         // will remove any temporary file if there were any
         clearUnsavedChanges();
     }
+
+#if 1
+    // Legacy support
+    // Remove #if-#endif section half a year after DRTVWR-501 releases.
+    // Update legacy settings in settings.xml
+    // We only care for third person view since legacy settings can't store
+    // more than one mode.
+    // We are saving this even if we are in temporary mode - preferences
+    // will restore values on cancel
+    if (mLoadMode == MODE_THIRD_PERSON)
+    {
+        bool value = canHandleMouse("walk_to", CLICK_DOUBLELEFT, MASK_NONE);
+        gSavedSettings.setBOOL("DoubleClickAutoPilot", value);
+
+        value = canHandleMouse("walk_to", CLICK_LEFT, MASK_NONE);
+        gSavedSettings.setBOOL("ClickToWalk", value);
+
+        value = canHandleMouse("teleport_to", CLICK_DOUBLELEFT, MASK_NONE);
+        gSavedSettings.setBOOL("DoubleClickTeleport", value);
+
+        // new method can save both toggle and push-to-talk values simultaneously,
+        // but legacy one can save only one. It also doesn't support mask.
+        LLKeyData data = getControl("toggle_voice", 0);
+        bool can_toggle = !data.isEmpty();
+        if (!can_toggle)
+        {
+            data = getControl("voice_follow_key", 0);
+        }
+
+        gSavedSettings.setBOOL("PushToTalkToggle", can_toggle);
+        if (data.isEmpty())
+        {
+            // legacy viewer has a bug that might crash it if NONE value is assigned.
+            // just reset to default
+            gSavedSettings.getControl("PushToTalkButton")->resetToDefault(false);
+        }
+        else
+        {
+            if (data.mKey != KEY_NONE)
+            {
+                gSavedSettings.setString("PushToTalkButton", LLKeyboard::stringFromKey(data.mKey));
+            }
+            else
+            {
+                std::string ctrl_value;
+                switch (data.mMouse)
+                {
+                case CLICK_MIDDLE:
+                    ctrl_value = "MiddleMouse";
+                    break;
+                case CLICK_BUTTON4:
+                    ctrl_value = "MouseButton4";
+                    break;
+                case CLICK_BUTTON5:
+                    ctrl_value = "MouseButton5";
+                    break;
+                default:
+                    ctrl_value = "MiddleMouse";
+                    break;
+                }
+                gSavedSettings.setString("PushToTalkButton", ctrl_value);
+            }
+        }
+    }
+#endif
 }
 
 LLKeyData LLKeyConflictHandler::getDefaultControl(const std::string &control_name, U32 index)
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index 73d59cc217..5451c16ae2 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -82,6 +82,18 @@ public:
     bool canAssignControl(const std::string &control_name);
     static bool isReservedByMenu(const KEY &key, const MASK &mask);
     static bool isReservedByMenu(const LLKeyData &data);
+
+    // @control_name - see REGISTER_KEYBOARD_ACTION in llviewerinput for avaliable options,
+    // usually this is just name of the function
+    // @data_index - single control (function) can have multiple key combinations trigering
+    // it, this index indicates combination function will change/add note that preferences
+    // floater can only display up to 3 options, but data_index can be bigger then that
+    // @mouse_ind - mouse action (middle click, MB5 etc)
+    // @key - keyboard key action
+    // @mask - shift/ctrl/alt flags
+    // @ignore_mask - Either to expect exact match (ctrl+K will not trigger if ctrl+shift+K
+    // is active) or ignore not expected masks as long as expected mask is present
+    // (ctrl+K will be triggered if ctrl+shift+K is active)
     bool registerControl(const std::string &control_name, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask, bool ignore_mask); //todo: return conflicts?
 
     LLKeyData getControl(const std::string &control_name, U32 data_index);
@@ -101,6 +113,10 @@ public:
     // 'temporary' does not support gSavedSettings, those are handled
     // by preferences, so 'temporary' is such case will simply not
     // reset mHasUnsavedChanges
+    //
+    // 'temporary' exists to support ability of live-editing settings in
+    // preferences: temporary for testing changes 'live' without saving them,
+    // then hitting ok/cancel and save/discard values permanently.
     void saveToSettings(bool apply_temporary = false);
 
     LLKeyData getDefaultControl(const std::string &control_name, U32 data_index);
-- 
cgit v1.2.3


From 6f06ccc10a40ebfb89f670149d816cf5f9e3716e Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Mon, 15 Jun 2020 20:22:39 +0300
Subject: SL-12085 Debug-log window position

---
 indra/llwindow/llwindowwin32.cpp | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 0b3936f8a5..d657c63207 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -1126,6 +1126,12 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
 	mPostQuit = FALSE;
 
 	// create window
+    LL_DEBUGS("Window") << "Creating window with X: " << window_rect.left
+        << " Y: " << window_rect.top
+        << " Width: " << (window_rect.right - window_rect.left)
+        << " Height: " << (window_rect.bottom - window_rect.top)
+        << " Fullscreen: " << mFullscreen
+        << LL_ENDL;
 	DestroyWindow(mWindowHandle);
 	mWindowHandle = CreateWindowEx(dw_ex_style,
 		mWindowClassName,
-- 
cgit v1.2.3


From b291bc32e96bf5eab50df74d118ba61c924c67fa Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Mon, 15 Jun 2020 20:35:58 +0300
Subject: SL-13418 Restored previously removed 'click on land' controls from
 'move & view'

According to UX UI engineer. Also adapted it to new system, but it needs a better solution.
---
 indra/newview/llfloaterpreference.cpp              | 212 ++++++++++++++++++++-
 indra/newview/llfloaterpreference.h                |  22 ++-
 indra/newview/llkeyconflict.cpp                    |  16 ++
 indra/newview/llkeyconflict.h                      |   5 +-
 .../default/xui/en/panel_preferences_move.xml      |  64 +++++++
 5 files changed, 312 insertions(+), 7 deletions(-)

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index dc5905b6e7..ed28756473 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -311,6 +311,8 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
 
 	sSkin = gSavedSettings.getString("SkinCurrent");
 
+	mCommitCallbackRegistrar.add("Pref.ClickActionChange",		boost::bind(&LLFloaterPreference::onClickActionChange, this));
+
 	gSavedSettings.getControl("NameTagShowUsernames")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged,  _2));	
 	gSavedSettings.getControl("NameTagShowFriends")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged,  _2));	
 	gSavedSettings.getControl("UseDisplayNames")->getCommitSignal()->connect(boost::bind(&handleDisplayNamesOptionChanged,  _2));
@@ -609,6 +611,8 @@ void LLFloaterPreference::cancel()
 	// reverts any changes to current skin
 	gSavedSettings.setString("SkinCurrent", sSkin);
 
+	updateClickActionViews();
+
 	LLFloaterPreferenceProxy * advanced_proxy_settings = LLFloaterReg::findTypedInstance<LLFloaterPreferenceProxy>("prefs_proxy");
 	if (advanced_proxy_settings)
 	{
@@ -690,6 +694,9 @@ void LLFloaterPreference::onOpen(const LLSD& key)
 	onChangeTextureFolder();
 	onChangeSoundFolder();
 	onChangeAnimationFolder();
+
+	// Load (double-)click to walk/teleport settings.
+	updateClickActionViews();
 	
 	// Enabled/disabled popups, might have been changed by user actions
 	// while preferences floater was closed.
@@ -1486,6 +1493,7 @@ void LLFloaterPreference::refresh()
 	{
 		advanced->refresh();
 	}
+    updateClickActionViews();
 }
 
 void LLFloaterPreferenceGraphicsAdvanced::refresh()
@@ -1995,6 +2003,11 @@ void LLFloaterPreference::onClickAdvanced()
 	}
 }
 
+void LLFloaterPreference::onClickActionChange()
+{
+    updateClickActionControls();
+}
+
 void LLFloaterPreference::onClickPermsDefault()
 {
 	LLFloaterReg::showInstance("perms_default");
@@ -2032,6 +2045,86 @@ void LLFloaterPreference::onLogChatHistorySaved()
 	}
 }
 
+void LLFloaterPreference::updateClickActionControls()
+{
+    const int single_clk_action = getChild<LLComboBox>("single_click_action_combo")->getValue().asInteger();
+    const int double_clk_action = getChild<LLComboBox>("double_click_action_combo")->getValue().asInteger();
+
+    // Todo: This is a very ugly way to get access to keybindings.
+    // Reconsider possible options.
+    // Potential option: make constructor of LLKeyConflictHandler private
+    // but add a getter that will return shared pointer for specific
+    // mode, pointer should only exist so long as there are external users.
+    // In such case we won't need to do this 'dynamic_cast' nightmare.
+    // updateTable() can also be avoided
+    LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
+    for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin();
+        iter != tabcontainer->getChildList()->end(); ++iter)
+    {
+        LLView* view = *iter;
+        LLPanelPreferenceControls* panel = dynamic_cast<LLPanelPreferenceControls*>(view);
+        if (panel)
+        {
+            panel->setKeyBind("walk_to",
+                              EMouseClickType::CLICK_LEFT,
+                              KEY_NONE,
+                              MASK_NONE,
+                              single_clk_action == 1);
+            
+            panel->setKeyBind("walk_to",
+                              EMouseClickType::CLICK_DOUBLELEFT,
+                              KEY_NONE,
+                              MASK_NONE,
+                              double_clk_action == 1);
+            
+            panel->setKeyBind("teleport_to",
+                              EMouseClickType::CLICK_DOUBLELEFT,
+                              KEY_NONE,
+                              MASK_NONE,
+                              double_clk_action == 2);
+
+            panel->updateTable();
+        }
+    }
+}
+
+void LLFloaterPreference::updateClickActionViews()
+{
+    bool click_to_walk = false;
+    bool dbl_click_to_walk = false;
+    bool dbl_click_to_teleport = false;
+
+    // Todo: This is a very ugly way to get access to keybindings.
+    // Reconsider possible options.
+    LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
+    for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin();
+        iter != tabcontainer->getChildList()->end(); ++iter)
+    {
+        LLView* view = *iter;
+        LLPanelPreferenceControls* panel = dynamic_cast<LLPanelPreferenceControls*>(view);
+        if (panel)
+        {
+            click_to_walk = panel->canKeyBindHandle("walk_to",
+                EMouseClickType::CLICK_LEFT,
+                KEY_NONE,
+                MASK_NONE);
+
+            dbl_click_to_walk = panel->canKeyBindHandle("walk_to",
+                EMouseClickType::CLICK_DOUBLELEFT,
+                KEY_NONE,
+                MASK_NONE);
+
+            dbl_click_to_teleport = panel->canKeyBindHandle("teleport_to",
+                EMouseClickType::CLICK_DOUBLELEFT,
+                KEY_NONE,
+                MASK_NONE);
+        }
+    }
+
+	getChild<LLComboBox>("single_click_action_combo")->setValue((int)click_to_walk);
+	getChild<LLComboBox>("double_click_action_combo")->setValue(dbl_click_to_teleport ? 2 : (int)dbl_click_to_walk);
+}
+
 void LLFloaterPreference::applyUIColor(LLUICtrl* ctrl, const LLSD& param)
 {
 	LLUIColorTable::instance().setColor(param.asString(), LLColor4(ctrl->getValue()));
@@ -2856,7 +2949,7 @@ void LLPanelPreferenceControls::saveSettings()
     }
 
     S32 mode = pKeyModeBox->getValue().asInteger();
-    if (mConflictHandler[mode].empty())
+    if (mConflictHandler[mode].empty() || pControlsTable->isEmpty())
     {
         regenerateControls();
     }
@@ -2951,6 +3044,13 @@ void LLPanelPreferenceControls::onRestoreDefaultsResponse(const LLSD& notificati
             mConflictHandler[i].resetToDefaults();
             // Apply changes to viewer as 'temporary'
             mConflictHandler[i].saveToSettings(true);
+
+            // notify comboboxes in move&view about potential change
+            LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
+            if (instance)
+            {
+                instance->updateClickActionViews();
+            }
         }
 
         updateTable();
@@ -2960,6 +3060,16 @@ void LLPanelPreferenceControls::onRestoreDefaultsResponse(const LLSD& notificati
         // Apply changes to viewer as 'temporary'
         mConflictHandler[mEditingMode].saveToSettings(true);
 
+        if (mEditingMode == LLKeyConflictHandler::MODE_THIRD_PERSON)
+        {
+            // notify comboboxes in move&view about potential change
+            LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
+            if (instance)
+            {
+                instance->updateClickActionViews();
+            }
+        }
+
         updateTable();
         break;
     case 2: // Cancel
@@ -2969,7 +3079,80 @@ void LLPanelPreferenceControls::onRestoreDefaultsResponse(const LLSD& notificati
     }
 }
 
-// todo: copy onSetKeyBind to interface and inherit from interface
+// Bypass to let Move & view read values without need to create own key binding handler
+// Assumes third person view
+// Might be better idea to just move whole mConflictHandler into LLFloaterPreference
+bool LLPanelPreferenceControls::canKeyBindHandle(const std::string &control, EMouseClickType click, KEY key, MASK mask)
+{
+    S32 mode = LLKeyConflictHandler::MODE_THIRD_PERSON;
+    if (mConflictHandler[mode].empty())
+    {
+        // opening for first time
+        mConflictHandler[mode].loadFromSettings(LLKeyConflictHandler::MODE_THIRD_PERSON);
+    }
+
+    return mConflictHandler[mode].canHandleControl(control, click, key, mask);
+}
+
+// Bypass to let Move & view modify values without need to create own key binding handler
+// Assumes third person view
+// Might be better idea to just move whole mConflictHandler into LLFloaterPreference
+void LLPanelPreferenceControls::setKeyBind(const std::string &control, EMouseClickType click, KEY key, MASK mask, bool set)
+{
+    S32 mode = LLKeyConflictHandler::MODE_THIRD_PERSON;
+    if (mConflictHandler[mode].empty())
+    {
+        // opening for first time
+        mConflictHandler[mode].loadFromSettings(LLKeyConflictHandler::MODE_THIRD_PERSON);
+    }
+
+    if (!mConflictHandler[mode].canAssignControl(mEditingControl))
+    {
+        return;
+    }
+
+    bool already_recorded = mConflictHandler[mode].canHandleControl(control, click, key, mask);
+    if (set)
+    {
+        if (already_recorded)
+        {
+            // nothing to do
+            return;
+        }
+
+        // find free spot to add data, if no free spot, assign to first
+        S32 index = 0;
+        for (S32 i = 0; i < 3; i++)
+        {
+            if (mConflictHandler[mode].getControl(control, i).isEmpty())
+            {
+                index = i;
+                break;
+            }
+        }
+        mConflictHandler[mode].registerControl(control, index, click, key, mask, true);
+    }
+    else if (!set)
+    {
+        if (!already_recorded)
+        {
+            // nothing to do
+            return;
+        }
+
+        // find specific control and reset it
+        for (S32 i = 0; i < 3; i++)
+        {
+            LLKeyData data = mConflictHandler[mode].getControl(control, i);
+            if (data.mMouse == click && data.mKey == key && data.mMask == mask)
+            {
+                mConflictHandler[mode].clearControl(control, i);
+            }
+        }
+    }
+}
+
+// from LLSetKeybindDialog's interface
 bool LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes)
 {
     if (!mConflictHandler[mEditingMode].canAssignControl(mEditingControl))
@@ -3001,6 +3184,21 @@ bool LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MAS
     }
 
     updateTable();
+
+    if ((mEditingMode == LLKeyConflictHandler::MODE_THIRD_PERSON || all_modes)
+        && (mEditingControl == "walk_to"
+            || mEditingControl == "teleport_to"
+            || click == CLICK_LEFT
+            || click == CLICK_DOUBLELEFT))
+    {
+        // notify comboboxes in move&view about potential change
+        LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
+        if (instance)
+        {
+            instance->updateClickActionViews();
+        }
+    }
+
     return true;
 }
 
@@ -3034,6 +3232,16 @@ void LLPanelPreferenceControls::onDefaultKeyBind(bool all_modes)
         }
     }
     updateTable();
+
+    if (mEditingMode == LLKeyConflictHandler::MODE_THIRD_PERSON || all_modes)
+    {
+        // notify comboboxes in move&view about potential change
+        LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
+        if (instance)
+        {
+            instance->updateClickActionViews();
+        }
+    }
 }
 
 void LLPanelPreferenceControls::onCancelKeyBind()
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index ea6e1070cd..066deb97ee 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -106,6 +106,8 @@ public:
 	void selectPrivacyPanel();
 	void selectChatPanel();
 	void getControlNames(std::vector<std::string>& names);
+	// updates click/double-click action controls depending on values from settings.xml
+	void updateClickActionViews();
 
 protected:	
 	void		onBtnOK(const LLSD& userdata);
@@ -131,6 +133,11 @@ protected:
 	// callback for when client turns on impostors
 	void onAvatarImpostorsEnable();
 
+	// callback for commit in the "Single click on land" and "Double click on land" comboboxes.
+	void onClickActionChange();
+	// updates click/double-click action keybindngs depending on view values
+	void updateClickActionControls();
+
 public:
 	// This function squirrels away the current values of the controls so that
 	// cancel() can restore them.	
@@ -304,9 +311,20 @@ public:
 	void onModeCommit();
 	void onRestoreDefaultsBtn();
 	void onRestoreDefaultsResponse(const LLSD& notification, const LLSD& response);
+
+    // Bypass to let Move & view read values without need to create own key binding handler
+    // Todo: consider a better way to share access to keybindings
+    bool canKeyBindHandle(const std::string &control, EMouseClickType click, KEY key, MASK mask);
+    // Bypasses to let Move & view modify values without need to create own key binding handler
+    void setKeyBind(const std::string &control, EMouseClickType click, KEY key, MASK mask, bool set /*set or reset*/ );
+
+    // from interface
 	/*virtual*/ bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes);
     /*virtual*/ void onDefaultKeyBind(bool all_modes);
-	/*virtual*/ void onCancelKeyBind();
+    /*virtual*/ void onCancelKeyBind();
+
+    // Updates keybindings from storage to table
+    void updateTable();
 
 private:
 	// reloads settings, discards current changes, updates table
@@ -319,8 +337,6 @@ private:
 
 	// Cleans content and then adds content from xml files according to current mEditingMode
 	void populateControlTable();
-	// Updates keybindings from storage to table
-	void updateTable();
 
 	LLScrollListCtrl* pControlsTable;
 	LLComboBox *pKeyModeBox;
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index 5f966624ca..b426dc14fc 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -217,6 +217,22 @@ bool LLKeyConflictHandler::registerControl(const std::string &control_name, U32
     return false;
 }
 
+bool LLKeyConflictHandler::clearControl(const std::string &control_name, U32 data_index)
+{
+    if (control_name.empty())
+    {
+        return false;
+    }
+    LLKeyConflict &type_data = mControlsMap[control_name];
+    if (!type_data.mAssignable)
+    {
+        // Example: user tried to assign camera spin to all modes, but first person mode doesn't support it
+        return false;
+    }
+    type_data.mKeyBind.resetKeyData(data_index);
+    return true;
+}
+
 LLKeyData LLKeyConflictHandler::getControl(const std::string &control_name, U32 index)
 {
     if (control_name.empty())
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index 5451c16ae2..7566303cdd 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -86,8 +86,8 @@ public:
     // @control_name - see REGISTER_KEYBOARD_ACTION in llviewerinput for avaliable options,
     // usually this is just name of the function
     // @data_index - single control (function) can have multiple key combinations trigering
-    // it, this index indicates combination function will change/add note that preferences
-    // floater can only display up to 3 options, but data_index can be bigger then that
+    // it, this index indicates combination function will change/add; Note that preferences
+    // floater can only display up to 3 options, but data_index can be bigger than that
     // @mouse_ind - mouse action (middle click, MB5 etc)
     // @key - keyboard key action
     // @mask - shift/ctrl/alt flags
@@ -95,6 +95,7 @@ public:
     // is active) or ignore not expected masks as long as expected mask is present
     // (ctrl+K will be triggered if ctrl+shift+K is active)
     bool registerControl(const std::string &control_name, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask, bool ignore_mask); //todo: return conflicts?
+    bool clearControl(const std::string &control_name, U32 data_index);
 
     LLKeyData getControl(const std::string &control_name, U32 data_index);
 
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_move.xml b/indra/newview/skins/default/xui/en/panel_preferences_move.xml
index d106456b31..8794e3bf95 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_move.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_move.xml
@@ -195,6 +195,70 @@
    name="invert_mouse"
    top_delta="0"
    width="128" />
+  <text
+   follows="left|top"
+   type="string"
+   length="1"
+   height="10"
+   layout="topleft"
+   left="86"
+   name="single_click_action_lbl"
+   width="150"
+   top_pad="20">
+    Single click on land:
+  </text>
+  <combo_box
+   height="23"
+   layout="topleft"
+   left_pad="10"
+   top_delta="-6"
+   name="single_click_action_combo"
+   width="200">
+    <combo_box.item
+     label="No action"
+     name="0"
+     value="0"/>
+    <combo_box.item
+     label="Move to clicked point"
+     name="1"
+     value="1"/>
+    <combo_box.commit_callback
+     function="Pref.ClickActionChange"/>
+  </combo_box>
+  <text
+   follows="left|top"
+   type="string"
+   length="1"
+   height="10"
+   layout="topleft"
+   left="86"
+   name="double_click_action_lbl"
+   width="150"
+   top_pad="12">
+    Double click on land:
+  </text>
+  <combo_box
+   height="23"
+   layout="topleft"
+   left_pad="10"
+   top_delta="-6"
+   name="double_click_action_combo"
+   width="200">
+    <combo_box.item
+     label="No action"
+     name="0"
+     value="0"/>
+    <combo_box.item
+     label="Move to clicked point"
+     name="1"
+     value="1"/>
+    <combo_box.item
+     label="Teleport to clicked point"
+     name="2"
+     value="2"/>
+    <combo_box.commit_callback
+     function="Pref.ClickActionChange"/>
+  </combo_box>
   <button
    height="23"
    label="Other Devices"
-- 
cgit v1.2.3


From 71b66c758e52f6ad79392942646d8db021897dea Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 16 Jun 2020 09:27:41 +0300
Subject: SL-13418 Move and view panel now applies changes on the go

---
 indra/newview/llappviewer.cpp         | 4 ++--
 indra/newview/llfloaterpreference.cpp | 9 ++++++++-
 indra/newview/llfloaterpreference.h   | 9 +++++----
 indra/newview/llkeyconflict.cpp       | 1 +
 4 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 775b6db94b..f81f9557ff 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1014,8 +1014,8 @@ bool LLAppViewer::init()
     // Also part of backward compatibility is present in LLKeyConflictHandler to modify
     // legacy variables on changes in new system (to make sure we won't enforce
     // legacy values again if user dropped to defaults in new system)
-    if (mIsFirstRun
-        && !gDirUtilp->fileExists(key_bindings_file)) // if file is missing, assume that there were no changes by user yet
+    if (LLVersionInfo::getChannelAndVersion() != gLastRunVersion
+        || !gDirUtilp->fileExists(key_bindings_file)) // if file is missing, assume that there were no changes by user yet
     {
         // copy mouse actions and voice key changes to new file
         LL_INFOS("InitInfo") << "Converting legacy mouse bindings to new format" << LL_ENDL;
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index ed28756473..a1d3c65289 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2083,7 +2083,7 @@ void LLFloaterPreference::updateClickActionControls()
                               MASK_NONE,
                               double_clk_action == 2);
 
-            panel->updateTable();
+            panel->updateAndApply();
         }
     }
 }
@@ -3152,6 +3152,13 @@ void LLPanelPreferenceControls::setKeyBind(const std::string &control, EMouseCli
     }
 }
 
+void LLPanelPreferenceControls::updateAndApply()
+{
+    S32 mode = LLKeyConflictHandler::MODE_THIRD_PERSON;
+    mConflictHandler[mode].saveToSettings(true);
+    updateTable();
+}
+
 // from LLSetKeybindDialog's interface
 bool LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes)
 {
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 066deb97ee..1268935712 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -317,15 +317,13 @@ public:
     bool canKeyBindHandle(const std::string &control, EMouseClickType click, KEY key, MASK mask);
     // Bypasses to let Move & view modify values without need to create own key binding handler
     void setKeyBind(const std::string &control, EMouseClickType click, KEY key, MASK mask, bool set /*set or reset*/ );
+    void updateAndApply();
 
     // from interface
 	/*virtual*/ bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes);
     /*virtual*/ void onDefaultKeyBind(bool all_modes);
     /*virtual*/ void onCancelKeyBind();
 
-    // Updates keybindings from storage to table
-    void updateTable();
-
 private:
 	// reloads settings, discards current changes, updates table
 	void regenerateControls();
@@ -336,7 +334,10 @@ private:
 	void addControlTableSeparator();
 
 	// Cleans content and then adds content from xml files according to current mEditingMode
-	void populateControlTable();
+    void populateControlTable();
+
+    // Updates keybindings from storage to table
+    void updateTable();
 
 	LLScrollListCtrl* pControlsTable;
 	LLComboBox *pKeyModeBox;
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index b426dc14fc..4c055fcee6 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -230,6 +230,7 @@ bool LLKeyConflictHandler::clearControl(const std::string &control_name, U32 dat
         return false;
     }
     type_data.mKeyBind.resetKeyData(data_index);
+    mHasUnsavedChanges = true;
     return true;
 }
 
-- 
cgit v1.2.3


From d202f460e2a2d6cf034bfb6061b8a50a36a053b4 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 16 Jun 2020 23:52:29 +0300
Subject: SL-12085 Debug log for show() and PeekMessage

User's viewer freezes right after setStartupState( STATE_LOGIN_CLEANUP ) and these places are primary suspects
---
 indra/llwindow/llwindowwin32.cpp  | 1 +
 indra/newview/llstartup.cpp       | 6 +++++-
 indra/newview/llviewerdisplay.cpp | 1 +
 3 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index d657c63207..d3cf1d49e4 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -714,6 +714,7 @@ LLWindowWin32::~LLWindowWin32()
 
 void LLWindowWin32::show()
 {
+    LL_DEBUGS("Window") << "Setting window to show" << LL_ENDL;
 	ShowWindow(mWindowHandle, SW_SHOW);
 	SetForegroundWindow(mWindowHandle);
 	SetFocus(mWindowHandle);
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index d44c81d1a4..4c54d44ac5 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -811,6 +811,7 @@ bool idle_startup()
 		show_debug_menus();
 
 		// Hide the splash screen
+		LL_DEBUGS("AppInit") << "Hide the splash screen and show window" << LL_ENDL;
 		LLSplashScreen::hide();
 		// Push our window frontmost
 		gViewerWindow->getWindow()->show();
@@ -818,9 +819,12 @@ bool idle_startup()
 		// DEV-16927.  The following code removes errant keystrokes that happen while the window is being 
 		// first made visible.
 #ifdef _WIN32
+        LL_DEBUGS("AppInit") << "Processing PeekMessage" << LL_ENDL;
 		MSG msg;
 		while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) )
-		{ }
+        {
+        }
+        LL_DEBUGS("AppInit") << "PeekMessage processed" << LL_ENDL;
 #endif
         display_startup();
         timeout.reset();
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 2b1f4b138f..4c7eb41418 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -253,6 +253,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 	if (gWindowResized)
 	{ //skip render on frames where window has been resized
+		LL_DEBUGS("Window") << "Resizing window" << LL_ENDL;
 		LL_RECORD_BLOCK_TIME(FTM_RESIZE_WINDOW);
 		gGL.flush();
 		glClear(GL_COLOR_BUFFER_BIT);
-- 
cgit v1.2.3


From a94a0a34c7eefc4540bd8200b8c13145ecbe2b4a Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 17 Jun 2020 01:22:16 +0300
Subject: SL-13418 Restored original default value for DoubleClickTeleport

---
 indra/newview/app_settings/settings.xml |  4 ++--
 indra/newview/llkeyconflict.cpp         | 27 +++++++++++++++++----------
 2 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 7cdb41b3cb..b1606a0f3c 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -3550,7 +3550,7 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    <key>DoubleClickTeleport</key>
+    <key>DoubleClickTeleport</key> 
     <map>
       <key>Comment</key>
       <string>Enable double-click to teleport where allowed (afects minimap and people panel)</string>
@@ -3559,7 +3559,7 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>1</integer>
+      <integer>0</integer>
     </map>
     <key>DoubleClickShowWorldMap</key>
     <map>
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index 4c055fcee6..8ee50d5c52 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -610,12 +610,6 @@ void LLKeyConflictHandler::saveToSettings(bool temporary)
         }
     }
 
-    if (!temporary)
-    {
-        // will remove any temporary file if there were any
-        clearUnsavedChanges();
-    }
-
 #if 1
     // Legacy support
     // Remove #if-#endif section half a year after DRTVWR-501 releases.
@@ -624,7 +618,7 @@ void LLKeyConflictHandler::saveToSettings(bool temporary)
     // more than one mode.
     // We are saving this even if we are in temporary mode - preferences
     // will restore values on cancel
-    if (mLoadMode == MODE_THIRD_PERSON)
+    if (mLoadMode == MODE_THIRD_PERSON && mHasUnsavedChanges)
     {
         bool value = canHandleMouse("walk_to", CLICK_DOUBLELEFT, MASK_NONE);
         gSavedSettings.setBOOL("DoubleClickAutoPilot", value);
@@ -632,9 +626,6 @@ void LLKeyConflictHandler::saveToSettings(bool temporary)
         value = canHandleMouse("walk_to", CLICK_LEFT, MASK_NONE);
         gSavedSettings.setBOOL("ClickToWalk", value);
 
-        value = canHandleMouse("teleport_to", CLICK_DOUBLELEFT, MASK_NONE);
-        gSavedSettings.setBOOL("DoubleClickTeleport", value);
-
         // new method can save both toggle and push-to-talk values simultaneously,
         // but legacy one can save only one. It also doesn't support mask.
         LLKeyData data = getControl("toggle_voice", 0);
@@ -680,6 +671,22 @@ void LLKeyConflictHandler::saveToSettings(bool temporary)
         }
     }
 #endif
+
+    if (mLoadMode == MODE_THIRD_PERSON && mHasUnsavedChanges)
+    {
+        // Map floater should react to doubleclick if doubleclick for teleport is set
+        // Todo: Seems conterintuitive for map floater to share inworld controls
+        // after these changes release, discuss with UI UX engineer if this should just
+        // be set to 1 by default (before release this also doubles as legacy support)
+        bool value = canHandleMouse("teleport_to", CLICK_DOUBLELEFT, MASK_NONE);
+        gSavedSettings.setBOOL("DoubleClickTeleport", value);
+    }
+
+    if (!temporary)
+    {
+        // will remove any temporary file if there were any
+        clearUnsavedChanges();
+    }
 }
 
 LLKeyData LLKeyConflictHandler::getDefaultControl(const std::string &control_name, U32 index)
-- 
cgit v1.2.3


From 1b744fb2a64f04332590b566783da2f955005414 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 17 Jun 2020 09:51:05 +0300
Subject: SL-13469 Fixed use of wrong clear function

---
 indra/newview/llfloaterpreference.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index a1d3c65289..91a3ae384d 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2934,7 +2934,8 @@ void LLPanelPreferenceControls::cancel()
             mConflictHandler[i].clear();
         }
     }
-    pControlsTable->clear();
+    pControlsTable->clearRows();
+    pControlsTable->clearColumns();
 }
 
 void LLPanelPreferenceControls::saveSettings()
-- 
cgit v1.2.3


From 9c57f89a7b214c9dda345a5a6cc94276e2061d1e Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 18 Jun 2020 20:50:54 +0300
Subject: SL-13481 Fixed mouselook teleport not having up to date data

---
 indra/newview/lltoolpie.cpp | 31 +++++++++++++++++++++++++++----
 1 file changed, 27 insertions(+), 4 deletions(-)

diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index dd429d4ccf..0839ea6cf5 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -547,10 +547,23 @@ bool LLToolPie::walkToClickedLocation()
     }
 
     LLPickInfo saved_pick = mPick;
-    mPick = gViewerWindow->pickImmediate(mHoverPick.mMousePt.mX, mHoverPick.mMousePt.mY,
-        FALSE /* ignore transparent */,
-        FALSE /* ignore rigged */,
-        FALSE /* ignore particles */);
+    if (gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK)
+    {
+        mPick = gViewerWindow->pickImmediate(mHoverPick.mMousePt.mX, mHoverPick.mMousePt.mY,
+            FALSE /* ignore transparent */,
+            FALSE /* ignore rigged */,
+            FALSE /* ignore particles */);
+    }
+    else
+    {
+        // We do not handle hover in mouselook as we do in other modes, so
+        // use croshair's position to do a pick
+        mPick = gViewerWindow->pickImmediate(gViewerWindow->getWorldViewRectScaled().getWidth() / 2,
+            gViewerWindow->getWorldViewRectScaled().getHeight() / 2,
+            FALSE /* ignore transparent */,
+            FALSE /* ignore rigged */,
+            FALSE /* ignore particles */);
+    }
 
     if (mPick.mPickType == LLPickInfo::PICK_OBJECT)
     {
@@ -609,6 +622,16 @@ bool LLToolPie::walkToClickedLocation()
 
 bool LLToolPie::teleportToClickedLocation()
 {
+    if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK)
+    {
+        // We do not handle hover in mouselook as we do in other modes, so
+        // use croshair's position to do a pick
+        BOOL pick_rigged = false;
+        mHoverPick = gViewerWindow->pickImmediate(gViewerWindow->getWorldViewRectScaled().getWidth() / 2,
+                                                  gViewerWindow->getWorldViewRectScaled().getHeight() / 2,
+                                                  FALSE,
+                                                  pick_rigged);
+    }
     LLViewerObject* objp = mHoverPick.getObject();
     LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL;
 
-- 
cgit v1.2.3


From f8137f68a0f157c7dc7766a695a62d59b4198291 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 23 Jun 2020 16:16:11 +0300
Subject: Reverted SL-6109 keybinding changes

Changes were moved to DRTVWR-514
---
 indra/llcommon/CMakeLists.txt                      |    2 -
 indra/llcommon/indra_constants.h                   |   11 -
 indra/llcommon/llkeybind.cpp                       |  395 -----
 indra/llcommon/llkeybind.h                         |  106 --
 indra/llui/llmenugl.cpp                            |   42 +-
 indra/llui/llmenugl.h                              |   18 +-
 indra/llui/llscrolllistcell.cpp                    |  149 +-
 indra/llui/llscrolllistcell.h                      |   31 +-
 indra/llui/llscrolllistctrl.cpp                    |  177 +--
 indra/llui/llscrolllistctrl.h                      |   21 +-
 indra/llui/llscrolllistitem.cpp                    |   56 +-
 indra/llui/llscrolllistitem.h                      |   21 +-
 indra/llwindow/llkeyboard.cpp                      |   88 +-
 indra/llwindow/llkeyboard.h                        |   16 +-
 indra/llwindow/llmousehandler.cpp                  |    2 +-
 indra/llwindow/llmousehandler.h                    |   12 +-
 indra/newview/CMakeLists.txt                       |   10 +-
 indra/newview/app_settings/key_bindings.xml        |  255 ----
 indra/newview/app_settings/keys.xml                |  363 +++++
 indra/newview/app_settings/settings.xml            |   10 +-
 indra/newview/llappviewer.cpp                      |  117 +-
 indra/newview/llfloaterpreference.cpp              |  874 +++--------
 indra/newview/llfloaterpreference.h                |   69 +-
 indra/newview/llkeyconflict.cpp                    |  989 -------------
 indra/newview/llkeyconflict.h                      |  174 ---
 indra/newview/llsetkeybinddialog.cpp               |  346 -----
 indra/newview/llsetkeybinddialog.h                 |  105 --
 indra/newview/llspatialpartition.cpp               |    2 +-
 indra/newview/lltool.cpp                           |    8 +-
 indra/newview/lltool.h                             |    2 +-
 indra/newview/lltoolpie.cpp                        |  258 ++--
 indra/newview/lltoolpie.h                          |    7 +-
 indra/newview/llviewerinput.cpp                    | 1528 --------------------
 indra/newview/llviewerinput.h                      |  177 ---
 indra/newview/llviewerkeyboard.cpp                 | 1039 +++++++++++++
 indra/newview/llviewerkeyboard.h                   |  118 ++
 indra/newview/llviewermenu.cpp                     |    1 +
 indra/newview/llviewerwindow.cpp                   |  114 +-
 indra/newview/llviewerwindow.h                     |    3 +-
 indra/newview/llvoiceclient.cpp                    |   65 +
 indra/newview/llvoiceclient.h                      |   10 +-
 indra/newview/llwindowlistener.cpp                 |    6 +-
 .../xui/en/control_table_contents_camera.xml       |  178 ---
 .../en/control_table_contents_camera_sitting.xml   |   65 -
 .../en/control_table_contents_columns_basic.xml    |   19 -
 .../xui/en/control_table_contents_editing.xml      |   80 -
 .../xui/en/control_table_contents_media.xml        |   76 -
 .../xui/en/control_table_contents_movement.xml     |  198 ---
 .../skins/default/xui/en/floater_preferences.xml   |    7 -
 .../skins/default/xui/en/floater_select_key.xml    |   63 +-
 .../newview/skins/default/xui/en/notifications.xml |   13 -
 .../default/xui/en/panel_preferences_controls.xml  |   63 -
 .../default/xui/en/panel_preferences_sound.xml     |   41 +-
 indra/newview/skins/default/xui/en/strings.xml     |    9 -
 54 files changed, 2240 insertions(+), 6369 deletions(-)
 delete mode 100644 indra/llcommon/llkeybind.cpp
 delete mode 100644 indra/llcommon/llkeybind.h
 delete mode 100644 indra/newview/app_settings/key_bindings.xml
 create mode 100644 indra/newview/app_settings/keys.xml
 delete mode 100644 indra/newview/llkeyconflict.cpp
 delete mode 100644 indra/newview/llkeyconflict.h
 delete mode 100644 indra/newview/llsetkeybinddialog.cpp
 delete mode 100644 indra/newview/llsetkeybinddialog.h
 delete mode 100644 indra/newview/llviewerinput.cpp
 delete mode 100644 indra/newview/llviewerinput.h
 create mode 100644 indra/newview/llviewerkeyboard.cpp
 create mode 100644 indra/newview/llviewerkeyboard.h
 delete mode 100644 indra/newview/skins/default/xui/en/control_table_contents_camera.xml
 delete mode 100644 indra/newview/skins/default/xui/en/control_table_contents_camera_sitting.xml
 delete mode 100644 indra/newview/skins/default/xui/en/control_table_contents_columns_basic.xml
 delete mode 100644 indra/newview/skins/default/xui/en/control_table_contents_editing.xml
 delete mode 100644 indra/newview/skins/default/xui/en/control_table_contents_media.xml
 delete mode 100644 indra/newview/skins/default/xui/en/control_table_contents_movement.xml
 delete mode 100644 indra/newview/skins/default/xui/en/panel_preferences_controls.xml

diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 7e52a620db..af41b9e460 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -73,7 +73,6 @@ set(llcommon_SOURCE_FILES
     llinitparam.cpp
     llinitdestroyclass.cpp
     llinstancetracker.cpp
-    llkeybind.cpp
     llleap.cpp
     llleaplistener.cpp
     llliveappconfig.cpp
@@ -184,7 +183,6 @@ set(llcommon_HEADER_FILES
     llinitdestroyclass.h
     llinitparam.h
     llinstancetracker.h
-    llkeybind.h
     llkeythrottle.h
     llleap.h
     llleaplistener.h
diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h
index 10b98f49aa..e7b0e0ef8e 100644
--- a/indra/llcommon/indra_constants.h
+++ b/indra/llcommon/indra_constants.h
@@ -54,17 +54,6 @@ enum ETerrainBrushType
 	E_LANDBRUSH_INVALID = 6
 };
 
-enum EMouseClickType{
-    CLICK_NONE = -1,
-    CLICK_LEFT = 0,
-    CLICK_MIDDLE,
-    CLICK_RIGHT,
-    CLICK_BUTTON4,
-    CLICK_BUTTON5,
-    CLICK_DOUBLELEFT,
-    CLICK_COUNT // 'size', CLICK_NONE does not counts
-};
-
 // keys
 // Bit masks for various keyboard modifier keys.
 const MASK MASK_NONE =			0x0000;
diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp
deleted file mode 100644
index ecfc289cb3..0000000000
--- a/indra/llcommon/llkeybind.cpp
+++ /dev/null
@@ -1,395 +0,0 @@
-/** 
- * @file llkeybind.cpp
- * @brief Information about key combinations.
- *
- * $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$
- */
-
-#include "linden_common.h"
-
-#include "llkeybind.h"
-
-#include "llsd.h"
-#include "llsdutil.h"
-
-LLKeyData::LLKeyData()
-    :
-    mMouse(CLICK_NONE),
-    mKey(KEY_NONE),
-    mMask(MASK_NONE),
-    mIgnoreMasks(false)
-{
-}
-
-LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, MASK mask)
-    :
-    mMouse(mouse),
-    mKey(key),
-    mMask(mask),
-    mIgnoreMasks(false)
-{
-}
-
-LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, bool ignore_mask)
-    :
-    mMouse(mouse),
-    mKey(key),
-    mMask(MASK_NONE),
-    mIgnoreMasks(ignore_mask)
-{
-}
-
-LLKeyData::LLKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask)
-    :
-    mMouse(mouse),
-    mKey(key),
-    mMask(mask),
-    mIgnoreMasks(ignore_mask)
-{
-}
-
-LLKeyData::LLKeyData(const LLSD &key_data)
-{
-    if (key_data.has("mouse"))
-    {
-        mMouse = (EMouseClickType)key_data["mouse"].asInteger();
-    }
-    if (key_data.has("key"))
-    {
-        mKey = key_data["key"].asInteger();
-    }
-    if (key_data.has("ignore_accelerators"))
-    {
-        mIgnoreMasks = key_data["ignore_accelerators"];
-    }
-    if (key_data.has("mask"))
-    {
-        mMask = key_data["mask"].asInteger();
-    }
-}
-
-LLSD LLKeyData::asLLSD() const
-{
-    LLSD data;
-    data["mouse"] = (LLSD::Integer)mMouse;
-    data["key"] = (LLSD::Integer)mKey;
-    data["mask"] = (LLSD::Integer)mMask;
-    if (mIgnoreMasks)
-    {
-        data["ignore_accelerators"] = (LLSD::Boolean)mIgnoreMasks;
-    }
-    return data;
-}
-
-bool LLKeyData::isEmpty() const
-{
-    return mMouse == CLICK_NONE && mKey == KEY_NONE;
-}
-
-void LLKeyData::reset()
-{
-    mMouse = CLICK_NONE;
-    mKey = KEY_NONE;
-    mMask = MASK_NONE;
-    mIgnoreMasks = false;
-}
-
-LLKeyData& LLKeyData::operator=(const LLKeyData& rhs)
-{
-    mMouse = rhs.mMouse;
-    mKey = rhs.mKey;
-    mMask = rhs.mMask;
-    mIgnoreMasks = rhs.mIgnoreMasks;
-    return *this;
-}
-
-bool LLKeyData::operator==(const LLKeyData& rhs)
-{
-    if (mMouse != rhs.mMouse) return false;
-    if (mKey != rhs.mKey) return false;
-    if (mMask != rhs.mMask) return false;
-    if (mIgnoreMasks != rhs.mIgnoreMasks) return false;
-    return true;
-}
-
-bool LLKeyData::operator!=(const LLKeyData& rhs)
-{
-    if (mMouse != rhs.mMouse) return true;
-    if (mKey != rhs.mKey) return true;
-    if (mMask != rhs.mMask) return true;
-    if (mIgnoreMasks != rhs.mIgnoreMasks) return true;
-    return false;
-}
-
-bool LLKeyData::canHandle(const LLKeyData& data) const
-{
-    if (data.mKey == mKey
-        && data.mMouse == mMouse
-        && ((mIgnoreMasks && (data.mMask & mMask) == data.mMask) || data.mMask == mMask))
-    {
-        return true;
-    }
-    return false;
-}
-
-bool LLKeyData::canHandle(EMouseClickType mouse, KEY key, MASK mask) const
-{
-    if (mouse == mMouse
-        && key == mKey
-        && ((mIgnoreMasks && (mask & mMask) == mask) || mask == mMask))
-    {
-        return true;
-    }
-    return false;
-}
-
-// LLKeyBind
-
-LLKeyBind::LLKeyBind(const LLSD &key_bind)
-{
-    if (key_bind.isArray())
-    {
-        for (LLSD::array_const_iterator data = key_bind.beginArray(), endLists = key_bind.endArray();
-            data != endLists;
-            data++
-            )
-        {
-            mData.push_back(LLKeyData(*data));
-        }
-    }
-}
-
-bool LLKeyBind::operator==(const LLKeyBind& rhs)
-{
-    U32 size = mData.size();
-    if (size != rhs.mData.size()) return false;
-
-    for (U32 i = 0; i < size; i++)
-    {
-        if (mData[i] != rhs.mData[i]) return false;
-    }
-
-    return true;
-}
-
-bool LLKeyBind::operator!=(const LLKeyBind& rhs)
-{
-    U32 size = mData.size();
-    if (size != rhs.mData.size()) return true;
-
-    for (U32 i = 0; i < size; i++)
-    {
-        if (mData[i] != rhs.mData[i]) return true;
-    }
-
-    return false;
-}
-
-bool LLKeyBind::isEmpty() const
-{
-    for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
-    {
-        if (!iter->isEmpty()) return false;
-    }
-    return true;
-}
-
-LLSD LLKeyBind::asLLSD() const
-{
-    S32 last = mData.size() - 1;
-    while (mData[last].empty())
-    {
-        last--;
-    }
-
-    LLSD data;
-    for (S32 i = 0; i <= last; ++i)
-    {
-        // append even if empty to not affect visual representation
-        data.append(mData[i].asLLSD());
-    }
-    return data;
-}
-
-bool LLKeyBind::canHandle(EMouseClickType mouse, KEY key, MASK mask) const
-{
-    if (mouse == CLICK_NONE && key == KEY_NONE)
-    {
-        // assume placeholder
-        return false;
-    }
-
-    for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
-    {
-        if (iter->canHandle(mouse, key, mask))
-        {
-            return true;
-        }
-    }
-    return false;
-}
-
-bool LLKeyBind::canHandleKey(KEY key, MASK mask) const
-{
-    return canHandle(CLICK_NONE, key, mask);
-}
-
-bool LLKeyBind::canHandleMouse(EMouseClickType mouse, MASK mask) const
-{
-    return canHandle(mouse, KEY_NONE, mask);
-}
-
-bool LLKeyBind::hasKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const
-{
-    if (mouse != CLICK_NONE || key != KEY_NONE)
-    {
-        for (data_vector_t::const_iterator iter = mData.begin(); iter != mData.end(); iter++)
-        {
-            if (iter->mKey == key
-                && iter->mMask == mask
-                && iter->mMouse == mouse
-                && iter->mIgnoreMasks == ignore)
-            {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
-bool LLKeyBind::hasKeyData(const LLKeyData& data) const
-{
-    return hasKeyData(data.mMouse, data.mKey, data.mMask, data.mIgnoreMasks);
-}
-
-bool LLKeyBind::hasKeyData(U32 index) const
-{
-    return mData.size() > index;
-}
-
-S32 LLKeyBind::findKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const
-{
-    if (mouse != CLICK_NONE || key != KEY_NONE)
-    {
-        for (S32 i = 0; i < mData.size(); ++i)
-        {
-            if (mData[i].mKey == key
-                && mData[i].mMask == mask
-                && mData[i].mMouse == mouse
-                && mData[i].mIgnoreMasks == ignore)
-            {
-                return i;
-            }
-        }
-    }
-    return -1;
-}
-
-S32 LLKeyBind::findKeyData(const LLKeyData& data) const
-{
-    return findKeyData(data.mMouse, data.mKey, data.mMask, data.mIgnoreMasks);
-}
-
-LLKeyData LLKeyBind::getKeyData(U32 index) const
-{
-    if (mData.size() > index)
-    {
-        return mData[index];
-    }
-    return LLKeyData();
-}
-
-bool LLKeyBind::addKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore)
-{
-    if (!hasKeyData(mouse, key, mask, ignore))
-    {
-        mData.push_back(LLKeyData(mouse, key, mask, ignore));
-        return true;
-    }
-    return false;
-}
-
-bool LLKeyBind::addKeyData(const LLKeyData& data)
-{
-    if (!hasKeyData(data))
-    {
-        mData.push_back(data);
-        return true;
-    }
-    return false;
-}
-
-void LLKeyBind::replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore, U32 index)
-{
-    replaceKeyData(LLKeyData(mouse, key, mask, ignore), index);
-}
-
-void LLKeyBind::replaceKeyData(const LLKeyData& data, U32 index)
-{
-    if (!data.isEmpty())
-    {
-        // if both click and key are none (isEmpty()), we are inserting a placeholder, we don't want to reset anything
-        // otherwise reset identical key
-        for (data_vector_t::iterator iter = mData.begin(); iter != mData.end(); iter++)
-        {
-            if (iter->mKey == data.mKey
-                && iter->mMouse == data.mMouse
-                && iter->mIgnoreMasks == data.mIgnoreMasks
-                && iter->mMask == data.mMask)
-            {
-                // Replacing only fully equal combinations even in case 'ignore' is set
-                // Reason: Simplicity and user might decide to do a 'move' command as W and Shift+Ctrl+W, and 'run' as Shift+W
-                iter->reset();
-                break;
-            }
-        }
-    }
-    if (mData.size() <= index)
-    {
-        mData.resize(index + 1);
-    }
-    mData[index] = data;
-}
-
-void LLKeyBind::resetKeyData(S32 index)
-{
-    if (mData.size() > index)
-    {
-        mData[index].reset();
-    }
-}
-
-void LLKeyBind::trimEmpty()
-{
-    S32 last = mData.size() - 1;
-    while (last >= 0 && mData[last].empty())
-    {
-        mData.erase(mData.begin() + last);
-        last--;
-    }
-}
-
-U32 LLKeyBind::getDataCount()
-{
-    return mData.size();
-}
-
diff --git a/indra/llcommon/llkeybind.h b/indra/llcommon/llkeybind.h
deleted file mode 100644
index c6b4bd970f..0000000000
--- a/indra/llcommon/llkeybind.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/** 
- * @file llkeybind.h
- * @brief Information about key combinations.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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_KEYBIND_H
-#define LL_KEYBIND_H
-
-#include "indra_constants.h"
-
-// KeyData - single key combination (mouse/mask/keyboard)
-class LL_COMMON_API LLKeyData
-{
-public:
-    LLKeyData();
-    LLKeyData(EMouseClickType mouse, KEY key, MASK mask);
-    LLKeyData(EMouseClickType mouse, KEY key, bool ignore_mask);
-    LLKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask);
-    LLKeyData(const LLSD &key_data);
-
-    LLSD asLLSD() const;
-    bool isEmpty() const;
-    bool empty() const { return isEmpty(); };
-    void reset();
-    LLKeyData& operator=(const LLKeyData& rhs);
-    bool operator==(const LLKeyData& rhs);
-    bool operator!=(const LLKeyData& rhs);
-
-    bool canHandle(const LLKeyData& data) const;
-    bool canHandle(EMouseClickType mouse, KEY key, MASK mask) const;
-
-    EMouseClickType mMouse;
-    KEY mKey;
-    MASK mMask;
-    // Either to expect exact match or ignore not expected masks as long as expected mask-bit is present
-    bool mIgnoreMasks; 
-};
-
-// One function can bind to multiple Key options
-class LLKeyBind
-{
-public:
-    LLKeyBind() {}
-    LLKeyBind(const LLSD &key_bind);
-
-    bool operator==(const LLKeyBind& rhs);
-    bool operator!=(const LLKeyBind& rhs);
-    bool isEmpty() const;
-    bool empty() const { return isEmpty(); };
-
-    LLSD asLLSD() const;
-
-    bool canHandle(EMouseClickType mouse, KEY key, MASK mask) const;
-    bool canHandleKey(KEY key, MASK mask) const;
-    bool canHandleMouse(EMouseClickType mouse, MASK mask) const;
-
-    // contains specified combination
-    bool hasKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const;
-    bool hasKeyData(const LLKeyData& data) const;
-    bool hasKeyData(U32 index) const;
-
-    // index of contained LLKeyData
-    S32 findKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore) const;
-    S32 findKeyData(const LLKeyData& data) const;
-
-    LLKeyData getKeyData(U32 index) const;
-
-    // these methods enshure there will be no repeats
-    bool addKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore);
-    bool addKeyData(const LLKeyData& data);
-    void replaceKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignore, U32 index);
-    void replaceKeyData(const LLKeyData& data, U32 index);
-    void resetKeyData(S32 index);
-    void clear() { mData.clear(); }
-    // if there any empty LLKeyData in the end of the array, remove them
-    void trimEmpty();
-    U32 getDataCount();
-
-private:
-    typedef std::vector<LLKeyData> data_vector_t;
-    data_vector_t mData;
-};
-
-
-#endif // LL_KEYBIND_H
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index b87819102b..5568a84494 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -212,12 +212,6 @@ LLSD LLMenuItemGL::getValue() const
 	return getLabel();
 }
 
-//virtual
-bool LLMenuItemGL::hasAccelerator(const KEY &key, const MASK &mask) const
-{
-	return (mAcceleratorKey == key) && (mAcceleratorMask == mask);
-}
-
 //virtual
 BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask)
 {
@@ -269,13 +263,13 @@ BOOL LLMenuItemGL::handleRightMouseUp(S32 x, S32 y, MASK mask)
 
 // This function checks to see if the accelerator key is already in use;
 // if not, it will be added to the list
-BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp)
+BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLKeyBinding*> *listp)
 {
-	LLMenuKeyboardBinding *accelerator = NULL;
+	LLKeyBinding *accelerator = NULL;
 
 	if (mAcceleratorKey != KEY_NONE)
 	{
-		std::list<LLMenuKeyboardBinding*>::iterator list_it;
+		std::list<LLKeyBinding*>::iterator list_it;
 		for (list_it = listp->begin(); list_it != listp->end(); ++list_it)
 		{
 			accelerator = *list_it;
@@ -299,7 +293,7 @@ BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *list
 		}
 		if (!accelerator)
 		{				
-			accelerator = new LLMenuKeyboardBinding;
+			accelerator = new LLKeyBinding;
 			if (accelerator)
 			{
 				accelerator->mKey = mAcceleratorKey;
@@ -1023,11 +1017,6 @@ BOOL LLMenuItemBranchGL::handleMouseUp(S32 x, S32 y, MASK mask)
 	return TRUE;
 }
 
-bool LLMenuItemBranchGL::hasAccelerator(const KEY &key, const MASK &mask) const
-{
-	return getBranch() && getBranch()->hasAccelerator(key, mask);
-}
-
 BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask)
 {
 	return getBranch() && getBranch()->handleAcceleratorKey(key, mask);
@@ -1035,7 +1024,7 @@ BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask)
 
 // This function checks to see if the accelerator key is already in use;
 // if not, it will be added to the list
-BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp)
+BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list<LLKeyBinding*> *listp)
 {
 	LLMenuGL* branch = getBranch();
 	if (!branch)
@@ -3034,27 +3023,6 @@ void LLMenuGL::updateParent(LLView* parentp)
 	}
 }
 
-bool LLMenuGL::hasAccelerator(const KEY &key, const MASK &mask) const
-{
-	if (key == KEY_NONE)
-	{
-		return false;
-	}
-	// Note: checking this way because mAccelerators seems to be broken
-	// mAccelerators probably needs to be cleaned up or fixed
-	// It was used for dupplicate accelerator avoidance.
-	item_list_t::const_iterator item_iter;
-	for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
-	{
-		LLMenuItemGL* itemp = *item_iter;
-		if (itemp->hasAccelerator(key, mask))
-		{
-			return true;
-		}
-	}
-	return false;
-}
-
 BOOL LLMenuGL::handleAcceleratorKey(KEY key, MASK mask)
 {
 	// don't handle if not enabled
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 8cef9c6463..1f11f26192 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -42,13 +42,6 @@
 extern S32 MENU_BAR_HEIGHT;
 extern S32 MENU_BAR_WIDTH;
 
-class LLMenuKeyboardBinding
-{
-public:
-    KEY				mKey;
-    MASK			mMask;
-};
-
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLMenuItemGL
 //
@@ -98,7 +91,6 @@ public:
 	/*virtual*/ void setValue(const LLSD& value);
 	/*virtual*/ LLSD getValue() const;
 
-	virtual bool hasAccelerator(const KEY &key, const MASK &mask) const;
 	virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
 
 	LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); }
@@ -117,7 +109,7 @@ public:
 	virtual void setBriefItem(BOOL brief);
 	virtual BOOL isBriefItem() const;
 
-	virtual BOOL addToAcceleratorList(std::list<LLMenuKeyboardBinding*> *listp);
+	virtual BOOL addToAcceleratorList(std::list<LLKeyBinding*> *listp);
 	void setAllowKeyRepeat(BOOL allow) { mAllowKeyRepeat = allow; }
 	BOOL getAllowKeyRepeat() const { return mAllowKeyRepeat; }
 
@@ -444,8 +436,7 @@ public:
 	/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
 	/*virtual*/ void removeChild( LLView* ctrl);
 	/*virtual*/ BOOL postBuild();
-	
-	virtual bool hasAccelerator(const KEY &key, const MASK &mask) const;
+
 	virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
 
 	LLMenuGL* findChildMenuByName(const std::string& name, BOOL recurse) const;
@@ -637,11 +628,10 @@ public:
 	
 	virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
 
-	virtual bool hasAccelerator(const KEY &key, const MASK &mask) const;
 	virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
 
 	// check if we've used these accelerators already
-	virtual BOOL addToAcceleratorList(std::list <LLMenuKeyboardBinding*> *listp);
+	virtual BOOL addToAcceleratorList(std::list <LLKeyBinding*> *listp);
 
 	// called to rebuild the draw label
 	virtual void buildDrawLabel( void );
@@ -807,7 +797,7 @@ private:
 
 	void checkMenuTrigger();
 
-	std::list <LLMenuKeyboardBinding*>	mAccelerators;
+	std::list <LLKeyBinding*>	mAccelerators;
 	BOOL						mAltKeyTrigger;
 };
 
diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp
index 13839da400..8000efad0e 100644
--- a/indra/llui/llscrolllistcell.cpp
+++ b/indra/llui/llscrolllistcell.cpp
@@ -50,10 +50,6 @@ LLScrollListCell* LLScrollListCell::create(const LLScrollListCell::Params& cell_
 	{
 		cell = new LLScrollListDate(cell_p);
 	}
-	else if (cell_p.type() == "icontext")
-	{
-		cell = new LLScrollListIconText(cell_p);
-	}
 	else	// default is "text"
 	{
 		cell = new LLScrollListText(cell_p);
@@ -172,7 +168,7 @@ U32 LLScrollListText::sCount = 0;
 
 LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p)
 :	LLScrollListCell(p),
-	mText(p.label.isProvided() ? p.label() : p.value().asString()),
+	mText(p.value().asString()),
 	mFont(p.font),
 	mColor(p.color),
 	mUseColor(p.color.isProvided()),
@@ -196,7 +192,7 @@ LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p)
 void LLScrollListText::highlightText(S32 offset, S32 num_chars)
 {
 	mHighlightOffset = offset;
-	mHighlightCount = llmax(0, num_chars);
+	mHighlightCount = num_chars;
 }
 
 //virtual 
@@ -296,12 +292,11 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col
 
 	if (mHighlightCount > 0)
 	{
-		// Highlight text
 		S32 left = 0;
 		switch(mFontAlignment)
 		{
 		case LLFontGL::LEFT:
-			left = mFont->getWidth(mText.getString(), 1, mHighlightOffset);
+			left = mFont->getWidth(mText.getString(), 0, mHighlightOffset);
 			break;
 		case LLFontGL::RIGHT:
 			left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX);
@@ -324,7 +319,7 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col
 	switch(mFontAlignment)
 	{
 	case LLFontGL::LEFT:
-		start_x = 1.f;
+		start_x = 0.f;
 		break;
 	case LLFontGL::RIGHT:
 		start_x = (F32)getWidth();
@@ -440,139 +435,3 @@ const LLSD LLScrollListDate::getValue() const
 {
 	return mDate;
 }
-
-//
-// LLScrollListIconText
-//
-LLScrollListIconText::LLScrollListIconText(const LLScrollListCell::Params& p)
-    : LLScrollListText(p),
-    mIcon(p.value().isUUID() ? LLUI::getUIImageByID(p.value().asUUID()) : LLUI::getUIImage(p.value().asString())),
-    mPad(4)
-{
-    mTextWidth = getWidth() - mPad /*padding*/ - mFont->getLineHeight();
-}
-
-LLScrollListIconText::~LLScrollListIconText()
-{
-}
-
-const LLSD LLScrollListIconText::getValue() const
-{
-    if (mIcon.isNull())
-    {
-        return LLStringUtil::null;
-    }
-    return mIcon->getName();
-}
-
-void LLScrollListIconText::setValue(const LLSD& value)
-{
-    if (value.isUUID())
-    {
-        // don't use default image specified by LLUUID::null, use no image in that case
-        LLUUID image_id = value.asUUID();
-        mIcon = image_id.notNull() ? LLUI::getUIImageByID(image_id) : LLUIImagePtr(NULL);
-    }
-    else
-    {
-        std::string value_string = value.asString();
-        if (LLUUID::validate(value_string))
-        {
-            setValue(LLUUID(value_string));
-        }
-        else if (!value_string.empty())
-        {
-            mIcon = LLUI::getUIImage(value.asString());
-        }
-        else
-        {
-            mIcon = NULL;
-        }
-    }
-}
-
-void LLScrollListIconText::setWidth(S32 width)
-{
-    LLScrollListCell::setWidth(width);
-    // Assume that iamge height and width is identical to font height and width
-    mTextWidth = width - mPad /*padding*/ - mFont->getLineHeight();
-}
-
-
-void LLScrollListIconText::draw(const LLColor4& color, const LLColor4& highlight_color)	 const
-{
-    LLColor4 display_color;
-    if (mUseColor)
-    {
-        display_color = mColor;
-    }
-    else
-    {
-        display_color = color;
-    }
-
-    S32 icon_height = mFont->getLineHeight();
-    S32 icon_space = mIcon ? (icon_height + mPad) : 0;
-
-    if (mHighlightCount > 0)
-    {
-        S32 left = 0;
-        switch (mFontAlignment)
-        {
-        case LLFontGL::LEFT:
-            left = mFont->getWidth(mText.getString(), icon_space + 1, mHighlightOffset);
-            break;
-        case LLFontGL::RIGHT:
-            left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX) - icon_space;
-            break;
-        case LLFontGL::HCENTER:
-            left = (getWidth() - mFont->getWidth(mText.getString()) - icon_space) / 2;
-            break;
-        }
-        LLRect highlight_rect(left - 2,
-            mFont->getLineHeight() + 1,
-            left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1,
-            1);
-        mRoundedRectImage->draw(highlight_rect, highlight_color);
-    }
-
-    // Try to draw the entire string
-    F32 right_x;
-    U32 string_chars = mText.length();
-    F32 start_text_x = 0.f;
-    S32 start_icon_x = 0;
-    switch (mFontAlignment)
-    {
-    case LLFontGL::LEFT:
-        start_text_x = icon_space + 1;
-        start_icon_x = 1;
-        break;
-    case LLFontGL::RIGHT:
-        start_text_x = (F32)getWidth();
-        start_icon_x = getWidth() - mFont->getWidth(mText.getString()) - icon_space;
-        break;
-    case LLFontGL::HCENTER:
-        F32 center = (F32)getWidth()* 0.5f;
-        start_text_x = center + ((F32)icon_space * 0.5f);
-        start_icon_x = center - (((F32)icon_space + mFont->getWidth(mText.getString())) * 0.5f);
-        break;
-    }
-    mFont->render(mText.getWString(), 0,
-        start_text_x, 0.f,
-        display_color,
-        mFontAlignment,
-        LLFontGL::BOTTOM,
-        0,
-        LLFontGL::NO_SHADOW,
-        string_chars,
-        getTextWidth(),
-        &right_x,
-        TRUE);
-
-    if (mIcon)
-    {
-        mIcon->draw(start_icon_x, 0, icon_height, icon_height, mColor);
-    }
-}
-
-
diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h
index 19576fb247..d625ebddcc 100644
--- a/indra/llui/llscrolllistcell.h
+++ b/indra/llui/llscrolllistcell.h
@@ -59,8 +59,7 @@ public:
 									visible;
 
 		Optional<void*>				userdata;
-		Optional<LLSD>				value; // state of checkbox, icon id/name, date
-		Optional<std::string>		label; // description or text
+		Optional<LLSD>				value;
 		Optional<std::string>		tool_tip;
 
 		Optional<const LLFontGL*>	font;
@@ -76,7 +75,6 @@ public:
 			enabled("enabled", true),
 			visible("visible", true),
 			value("value"),
-			label("label"),
 			tool_tip("tool_tip", ""),
 			font("font", LLFontGL::getFontSansSerifSmall()),
 			font_color("font_color", LLColor4::black),
@@ -154,12 +152,11 @@ public:
 	void			setText(const LLStringExplicit& text);
 	void			setFontStyle(const U8 font_style);
 
-protected:
+private:
 	LLUIString		mText;
 	S32				mTextWidth;
 	const LLFontGL*	mFont;
 	LLColor4		mColor;
-	LLColor4		mHighlightColor;
 	U8				mUseColor;
 	LLFontGL::HAlign mFontAlignment;
 	BOOL			mVisible;
@@ -172,7 +169,7 @@ protected:
 };
 
 /*
- * Cell displaying an image. AT the moment, this is specifically UI image
+ * Cell displaying an image.
  */
 class LLScrollListIcon : public LLScrollListCell
 {
@@ -226,26 +223,4 @@ private:
 	LLDate		mDate;
 };
 
-/*
-* Cell displaying icon and text.
-*/
-
-class LLScrollListIconText : public LLScrollListText
-{
-public:
-    LLScrollListIconText(const LLScrollListCell::Params& p);
-    /*virtual*/ ~LLScrollListIconText();
-    /*virtual*/ void	draw(const LLColor4& color, const LLColor4& highlight_color) const;
-    /*virtual*/ const LLSD		getValue() const;
-    /*virtual*/ void	setValue(const LLSD& value);
-
-
-    S32					getIconWidth() const;
-    /*virtual*/ void	setWidth(S32 width);/* { LLScrollListCell::setWidth(width); mTextWidth = width - ; }*/
-
-private:
-    LLPointer<LLUIImage>	mIcon;
-    S32						mPad;
-};
-
 #endif
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 83f80cfb9e..763c3aeb81 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -115,13 +115,6 @@ struct SortScrollListItem
 // LLScrollListCtrl
 //---------------------------------------------------------------------------
 
-void LLScrollListCtrl::SelectionTypeNames::declareValues()
-{
-    declare("row", LLScrollListCtrl::ROW);
-    declare("cell", LLScrollListCtrl::CELL);
-    declare("header", LLScrollListCtrl::HEADER);
-}
-
 LLScrollListCtrl::Contents::Contents()
 :	columns("column"),
 	rows("row")
@@ -135,10 +128,8 @@ LLScrollListCtrl::Params::Params()
 	has_border("draw_border"),
 	draw_heading("draw_heading"),
 	search_column("search_column", 0),
-	selection_type("selection_type", ROW),
 	sort_column("sort_column", -1),
 	sort_ascending("sort_ascending", true),
-	can_sort("can_sort", true),
 	mouse_wheel_opaque("mouse_wheel_opaque", false),
 	commit_on_keyboard_movement("commit_on_keyboard_movement", true),
 	heading_height("heading_height"),
@@ -173,10 +164,8 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
 	mCommitOnKeyboardMovement(p.commit_on_keyboard_movement),
 	mCommitOnSelectionChange(false),
 	mSelectionChanged(false),
-	mSelectionType(p.selection_type),
 	mNeedsScroll(false),
 	mCanSelect(true),
-	mCanSort(p.can_sort),
 	mColumnsDirty(false),
 	mMaxItemCount(INT_MAX), 
 	mBorderThickness( 2 ),
@@ -830,15 +819,7 @@ BOOL LLScrollListCtrl::selectFirstItem()
 		{
 			if (!itemp->getSelected())
 			{
-                switch (mSelectionType)
-                {
-                case CELL:
-                    selectItem(itemp, 0);
-                    break;
-                case HEADER:
-                case ROW:
-                    selectItem(itemp, -1);
-                }
+				selectItem(itemp);
 			}
 			success = TRUE;
 			mOriginalSelection = 0;
@@ -897,8 +878,7 @@ BOOL LLScrollListCtrl::selectItemRange( S32 first_index, S32 last_index )
 		{
 			if( itemp->getEnabled() )
 			{
-				// TODO: support range selection for cells
-				selectItem(itemp, -1, FALSE);
+				selectItem(itemp, FALSE);
 				success = TRUE;				
 			}
 		}
@@ -1024,14 +1004,10 @@ void LLScrollListCtrl::clearHighlightedItems()
 
 void LLScrollListCtrl::mouseOverHighlightNthItem(S32 target_index)
 {
-    if (mHighlightedItem != target_index)
-    {
-        if (mHighlightedItem >= 0 && mHighlightedItem < mItemList.size())
-        {
-            mItemList[mHighlightedItem]->setHoverCell(-1);
-        }
-        mHighlightedItem = target_index;
-    }
+	if (mHighlightedItem != target_index)
+	{
+		mHighlightedItem = target_index;
+	}
 }
 
 S32	LLScrollListCtrl::selectMultiple( uuid_vec_t ids )
@@ -1046,8 +1022,7 @@ S32	LLScrollListCtrl::selectMultiple( uuid_vec_t ids )
 		{
 			if (item->getEnabled() && (item->getUUID() == (*iditr)))
 			{
-				// TODO: support multiple selection for cells
-				selectItem(item, -1, FALSE);
+				selectItem(item,FALSE);
 				++count;
 				break;
 			}
@@ -1120,7 +1095,7 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection)
 			{
 				if (prev_item)
 				{
-					selectItem(prev_item, cur_item->getSelectedCell(), !extend_selection);
+					selectItem(prev_item, !extend_selection);
 				}
 				else
 				{
@@ -1164,7 +1139,7 @@ void LLScrollListCtrl::selectNextItem( BOOL extend_selection)
 			{
 				if (next_item)
 				{
-					selectItem(next_item, cur_item->getSelectedCell(), !extend_selection);
+					selectItem(next_item, !extend_selection);
 				}
 				else
 				{
@@ -1235,7 +1210,7 @@ BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sen
 	bool found = NULL != item;
 	if(found)
 	{
-		selectItem(item, -1);
+		selectItem(item);
 	}
 
 	if (mCommitOnSelectionChange)
@@ -1303,7 +1278,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
 			BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE;
 			if (select)
 			{
-				selectItem(item, -1);
+				selectItem(item);
 				found = TRUE;
 				break;
 			}
@@ -1343,7 +1318,7 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
 				// find offset of matching text (might have leading whitespace)
 				S32 offset = item_label.find(target_trimmed);
 				cellp->highlightText(offset, target_trimmed.size());
-				selectItem(item, -1);
+				selectItem(item);
 				found = TRUE;
 				break;
 			}
@@ -1409,7 +1384,7 @@ BOOL LLScrollListCtrl::setSelectedByValue(const LLSD& value, BOOL selected)
 		{
 			if (selected)
 			{
-				selectItem(item, -1);
+				selectItem(item);
 			}
 			else
 			{
@@ -1489,7 +1464,7 @@ void LLScrollListCtrl::drawItems()
 		
 		S32 max_columns = 0;
 
-		LLColor4 highlight_color = LLColor4::white; // ex: text inside cells
+		LLColor4 highlight_color = LLColor4::white;
 		static LLUICachedControl<F32> type_ahead_timeout ("TypeAheadTimeout", 0);
 		highlight_color.mV[VALPHA] = clamp_rescale(mSearchTimer.getElapsedTimeF32(), type_ahead_timeout * 0.7f, type_ahead_timeout(), 0.4f, 0.f);
 
@@ -1515,8 +1490,7 @@ void LLScrollListCtrl::drawItems()
 			max_columns = llmax(max_columns, item->getNumColumns());
 
 			LLColor4 fg_color;
-			LLColor4 hover_color(LLColor4::transparent);
-			LLColor4 select_color(LLColor4::transparent);
+			LLColor4 bg_color(LLColor4::transparent);
 
 			if( mScrollLines <= line && line < mScrollLines + num_page_lines )
 			{
@@ -1525,44 +1499,44 @@ void LLScrollListCtrl::drawItems()
 				{
 					if(item->getHighlighted())	// if it's highlighted, average the colors
 					{
-						select_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f);
+						bg_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f);
 					}
 					else						// otherwise just select-highlight it
 					{
-						select_color = mBgSelectedColor.get();
+						bg_color = mBgSelectedColor.get();
 					}
 
 					fg_color = (item->getEnabled() ? mFgSelectedColor.get() : mFgDisabledColor.get());
 				}
-				if (mHighlightedItem == line && mCanSelect)
+				else if (mHighlightedItem == line && mCanSelect)
 				{
 					if(item->getHighlighted())	// if it's highlighted, average the colors
 					{
-						hover_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f);
+						bg_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f);
 					}
 					else						// otherwise just hover-highlight it
 					{
-						hover_color = mHoveredColor.get();
+						bg_color = mHoveredColor.get();
 					}
 				}
 				else if (item->getHighlighted())
 				{
-					hover_color = mHighlightedColor.get();
+					bg_color = mHighlightedColor.get();
 				}
 				else 
 				{
 					if (mDrawStripes && (line % 2 == 0) && (max_columns > 1))
 					{
-						hover_color = mBgStripeColor.get();
+						bg_color = mBgStripeColor.get();
 					}
 				}
 
 				if (!item->getEnabled())
 				{
-					hover_color = mBgReadOnlyColor.get();
+					bg_color = mBgReadOnlyColor.get();
 				}
 
-				item->draw(item_rect, fg_color % alpha, hover_color% alpha, select_color% alpha, highlight_color % alpha, mColumnPadding);
+				item->draw(item_rect, fg_color % alpha, bg_color% alpha, highlight_color % alpha, mColumnPadding);
 
 				cur_y -= mLineHeight;
 			}
@@ -1714,7 +1688,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
 			{
 				if (mLastSelected == NULL)
 				{
-					selectItem(hit_item, getColumnIndexFromOffset(x));
+					selectItem(hit_item);
 				}
 				else
 				{
@@ -1738,7 +1712,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
 						LLScrollListItem *item = *itor;
                         if (item == hit_item || item == lastSelected)
 						{
-							selectItem(item, getColumnIndexFromOffset(x), FALSE);
+							selectItem(item, FALSE);
 							selecting = !selecting;
 							if (hit_item == lastSelected)
 							{
@@ -1748,7 +1722,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
 						}
 						if (selecting)
 						{
-							selectItem(item, getColumnIndexFromOffset(x), FALSE);
+							selectItem(item, FALSE);
 						}
 					}
 				}
@@ -1763,7 +1737,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
 				{
 					if(!(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable))
 					{
-						selectItem(hit_item, getColumnIndexFromOffset(x), FALSE);
+						selectItem(hit_item, FALSE);
 					}
 					else
 					{
@@ -1777,12 +1751,12 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
 			else
 			{
 				deselectAllItems(TRUE);
-				selectItem(hit_item, getColumnIndexFromOffset(x));
+				selectItem(hit_item);
 			}
 		}
 		else
 		{
-			selectItem(hit_item, getColumnIndexFromOffset(x));
+			selectItem(hit_item);
 		}
 
 		selection_changed = mSelectionChanged;
@@ -2150,29 +2124,8 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
 	{
 		LLScrollListItem* item = hitItem(x, y);
 		if (item)
-        {
-            mouseOverHighlightNthItem(getItemIndex(item));
-            switch (mSelectionType)
-            {
-            case CELL:
-                item->setHoverCell(getColumnIndexFromOffset(x));
-                break;
-            case HEADER:
-                {
-                    S32 cell = getColumnIndexFromOffset(x);
-                    if (cell > 0)
-                    {
-                        item->setHoverCell(cell);
-                    }
-                    else
-                    {
-                        item->setHoverCell(-1);
-                    }
-                    break;
-                }
-            case ROW:
-                break;
-            }
+		{
+			mouseOverHighlightNthItem(getItemIndex(item));
 		}
 		else
 		{
@@ -2220,52 +2173,6 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask )
 					handled = TRUE;
 				}
 				break;
-            case KEY_LEFT:
-                if (mAllowKeyboardMovement || hasFocus())
-                {
-                    // TODO: support multi-select
-                    LLScrollListItem *item = getFirstSelected();
-                    S32 cell = item->getSelectedCell();
-                    switch (mSelectionType)
-                    {
-                    case CELL:
-                        if (cell < mColumns.size()) cell++;
-                        break;
-                    case HEADER:
-                        if (cell == -1) cell = 1;
-                        else if (cell > 1 && cell < mColumns.size()) cell++; // skip header
-                        break;
-                    case ROW:
-                        cell = -1;
-                        break;
-                    }
-                    item->setSelectedCell(cell);
-                    handled = TRUE;
-                }
-                break;
-            case KEY_RIGHT:
-                if (mAllowKeyboardMovement || hasFocus())
-                {
-                    // TODO: support multi-select
-                    LLScrollListItem *item = getFirstSelected();
-                    S32 cell = item->getSelectedCell();
-                    switch (mSelectionType)
-                    {
-                    case CELL:
-                        if (cell >= 0) cell--;
-                        break;
-                    case HEADER:
-                        if (cell > 1) cell--;
-                        else if (cell == 1) cell = -1; // skip header
-                        break;
-                    case ROW:
-                        cell = -1;
-                        break;
-                    }
-                    item->setSelectedCell(cell);
-                    handled = TRUE;
-                }
-                break;
 			case KEY_PAGE_UP:
 				if (mAllowKeyboardMovement || hasFocus())
 				{
@@ -2434,7 +2341,7 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char)
 				LLWString item_label = utf8str_to_wstring(cellp->getValue().asString());
 				if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char)
 				{
-					selectItem(item, -1);
+					selectItem(item);
 					mNeedsScroll = true;
 					cellp->highlightText(0, 1);
 					mSearchTimer.reset();
@@ -2486,7 +2393,7 @@ BOOL LLScrollListCtrl::isRepeatedChars(const LLWString& string) const
 	return TRUE;
 }
 
-void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, S32 cell, BOOL select_single_item)
+void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, BOOL select_single_item)
 {
 	if (!itemp) return;
 
@@ -2505,18 +2412,6 @@ void LLScrollListCtrl::selectItem(LLScrollListItem* itemp, S32 cell, BOOL select
 			deselectAllItems(TRUE);
 		}
 		itemp->setSelected(TRUE);
-        switch (mSelectionType)
-        {
-        case CELL:
-            itemp->setSelectedCell(cell);
-            break;
-        case HEADER:
-            itemp->setSelectedCell(cell <= 0 ? -1 : cell);
-            break;
-        case ROW:
-            itemp->setSelectedCell(-1);
-            break;
-        }
 		mLastSelected = itemp;
 		mSelectionChanged = true;
 	}
@@ -2777,7 +2672,7 @@ void	LLScrollListCtrl::selectAll()
 		LLScrollListItem *itemp = *iter;
 		if( itemp->getEnabled() )
 		{
-			selectItem(itemp, -1, FALSE);
+			selectItem(itemp, FALSE);
 		}
 	}
 
@@ -2906,8 +2801,6 @@ void LLScrollListCtrl::onClickColumn(void *userdata)
 	LLScrollListCtrl *parent = info->mParentCtrl;
 	if (!parent) return;
 
-	if (!parent->mCanSort) return;
-
 	S32 column_index = info->mIndex;
 
 	LLScrollListColumn* column = parent->mColumnsIndexed[info->mIndex];
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index 45ce67349a..43e1c0d707 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -54,18 +54,6 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	public LLCtrlListInterface, public LLCtrlScrollInterface
 {
 public:
-    typedef enum e_selection_type
-    {
-        ROW, // default
-        CELL, // does not support multi-selection
-        HEADER, // when pointing to cells in column 0 will highlight whole row, otherwise cell, no multi-select
-    } ESelectionType;
-
-    struct SelectionTypeNames : public LLInitParam::TypeValuesHelper<LLScrollListCtrl::ESelectionType, SelectionTypeNames>
-    {
-        static void declareValues();
-    };
-
 	struct Contents : public LLInitParam::Block<Contents>
 	{
 		Multiple<LLScrollListColumn::Params>	columns;
@@ -111,8 +99,6 @@ public:
 						commit_on_keyboard_movement,
 						mouse_wheel_opaque;
 
-		Optional<ESelectionType, SelectionTypeNames> selection_type;
-
 		// display flags
 		Optional<bool>	has_border,
 						draw_heading,
@@ -129,8 +115,7 @@ public:
 		// sort and search behavior
 		Optional<S32>	search_column,
 						sort_column;
-		Optional<bool>	sort_ascending,
-						can_sort; // whether user is allowed to sort
+		Optional<bool>	sort_ascending;
 
 		// colors
 		Optional<LLUIColor>	fg_unselected_color,
@@ -447,7 +432,7 @@ private:
 	void            updateLineHeightInsert(LLScrollListItem* item);
 	void			reportInvalidInput();
 	BOOL			isRepeatedChars(const LLWString& string) const;
-	void			selectItem(LLScrollListItem* itemp, S32 cell, BOOL single_select = TRUE);
+	void			selectItem(LLScrollListItem* itemp, BOOL single_select = TRUE);
 	void			deselectItem(LLScrollListItem* itemp);
 	void			commitIfChanged();
 	BOOL			setSort(S32 column, BOOL ascending);
@@ -472,11 +457,9 @@ private:
 	bool			mCommitOnKeyboardMovement;
 	bool			mCommitOnSelectionChange;
 	bool			mSelectionChanged;
-	ESelectionType	mSelectionType;
 	bool			mNeedsScroll;
 	bool			mMouseWheelOpaque;
 	bool			mCanSelect;
-    bool			mCanSort;		// Whether user is allowed to sort
 	bool			mDisplayColumnHeaders;
 	bool			mColumnsDirty;
 	bool			mColumnWidthsDirty;
diff --git a/indra/llui/llscrolllistitem.cpp b/indra/llui/llscrolllistitem.cpp
index 51c615dd00..df22c88afb 100644
--- a/indra/llui/llscrolllistitem.cpp
+++ b/indra/llui/llscrolllistitem.cpp
@@ -40,8 +40,6 @@
 LLScrollListItem::LLScrollListItem( const Params& p )
 :	mSelected(FALSE),
 	mHighlighted(FALSE),
-	mHoverIndex(-1),
-	mSelectedIndex(-1),
 	mEnabled(p.enabled),
 	mUserdata(p.userdata),
 	mItemValue(p.value)
@@ -55,28 +53,6 @@ LLScrollListItem::~LLScrollListItem()
 	mColumns.clear();
 }
 
-void LLScrollListItem::setSelected(BOOL b)
-{
-    mSelected = b;
-    mSelectedIndex = -1;
-}
-
-void LLScrollListItem::setHighlighted(BOOL b)
-{
-    mHighlighted = b;
-    mHoverIndex = -1;
-}
-
-void LLScrollListItem::setHoverCell(S32 cell)
-{
-    mHoverIndex = cell;
-}
-
-void LLScrollListItem::setSelectedCell(S32 cell)
-{
-    mSelectedIndex = cell;
-}
-
 void LLScrollListItem::addColumn(const LLScrollListCell::Params& p)
 {
 	mColumns.push_back(LLScrollListCell::create(p));
@@ -144,21 +120,12 @@ std::string LLScrollListItem::getContentsCSV() const
 }
 
 
-void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& hover_color, const LLColor4& select_color, const LLColor4& highlight_color, S32 column_padding)
+void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding)
 {
 	// draw background rect
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	LLRect bg_rect = rect;
-    if (mSelectedIndex < 0 && getSelected())
-    {
-        // Whole item is highlighted/selected
-        gl_rect_2d(bg_rect, select_color);
-    }
-    else if (mHoverIndex < 0)
-    {
-        // Whole item is highlighted/selected
-        gl_rect_2d(bg_rect, hover_color);
-    }
+	gl_rect_2d( bg_rect, bg_color );
 
 	S32 cur_x = rect.mLeft;
 	S32 num_cols = getNumColumns();
@@ -174,25 +141,6 @@ void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const
 		{
 			LLUI::translate((F32) cur_x, (F32) rect.mBottom);
 
-            if (mSelectedIndex == cur_col)
-            {
-                // select specific cell
-                LLRect highlight_rect(0,
-                    cell->getHeight(),
-                    cell->getWidth(),
-                    0);
-                gl_rect_2d(highlight_rect, select_color);
-            }
-            else if (mHoverIndex == cur_col)
-            {
-                // highlight specific cell
-                LLRect highlight_rect(0,
-                    cell->getHeight(),
-                    cell->getWidth() ,
-                    0);
-                gl_rect_2d(highlight_rect, hover_color);
-            }
-
 			cell->draw( fg_color, highlight_color );
 		}
 		LLUI::popMatrix();
diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h
index d2c3dd7721..13655b5873 100644
--- a/indra/llui/llscrolllistitem.h
+++ b/indra/llui/llscrolllistitem.h
@@ -77,21 +77,15 @@ public:
 
 	virtual ~LLScrollListItem();
 
-	void	setSelected( BOOL b );
+	void	setSelected( BOOL b )			{ mSelected = b; }
 	BOOL	getSelected() const				{ return mSelected; }
 
 	void	setEnabled( BOOL b )			{ mEnabled = b; }
 	BOOL	getEnabled() const 				{ return mEnabled; }
 
-	void	setHighlighted( BOOL b );
+	void	setHighlighted( BOOL b )		{ mHighlighted = b; }
 	BOOL	getHighlighted() const			{ return mHighlighted; }
 
-	void	setSelectedCell( S32 cell );
-	S32		getSelectedCell() const			{ return mSelectedIndex; }
-
-	void	setHoverCell( S32 cell );
-	S32		getHoverCell() const			{ return mHoverIndex; }
-
 	void	setUserdata( void* userdata )	{ mUserdata = userdata; }
 	void*	getUserdata() const 			{ return mUserdata; }
 
@@ -113,21 +107,14 @@ public:
 
 	std::string getContentsCSV() const;
 
-	virtual void draw(const LLRect& rect,
-					  const LLColor4& fg_color,
-					  const LLColor4& hover_color, // highlight/hover selection of whole item or cell
-					  const LLColor4& select_color, // highlight/hover selection of whole item or cell
-					  const LLColor4& highlight_color, // highlights contents of cells (ex: text)
-					  S32 column_padding);
+	virtual void draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding);
 
 protected:
 	LLScrollListItem( const Params& );
 
 private:
 	BOOL	mSelected;
-    BOOL	mHighlighted;
-    S32		mHoverIndex;
-	S32		mSelectedIndex;
+	BOOL	mHighlighted;
 	BOOL	mEnabled;
 	void*	mUserdata;
 	LLSD	mItemValue;
diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp
index 5404ac50e5..f6f6c3931c 100644
--- a/indra/llwindow/llkeyboard.cpp
+++ b/indra/llwindow/llkeyboard.cpp
@@ -327,7 +327,7 @@ BOOL LLKeyboard::keyFromString(const std::string& str, KEY *key)
 
 
 // static
-std::string LLKeyboard::stringFromKey(KEY key, bool translate)
+std::string LLKeyboard::stringFromKey(KEY key)
 {
 	std::string res = get_if_there(sKeysToNames, key, std::string());
 	if (res.empty())
@@ -338,60 +338,16 @@ std::string LLKeyboard::stringFromKey(KEY key, bool translate)
 		res = std::string(buffer);
 	}
 
-	if (translate)
+	LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator;
+	if (trans != NULL)
 	{
-		LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator;
-		if (trans != NULL)
-		{
-			res = trans(res.c_str());
-		}
+		res = trans(res.c_str());
 	}
 
 	return res;
 }
 
-//static
-std::string LLKeyboard::stringFromAccelerator(MASK accel_mask)
-{
-    std::string res;
-
-    LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator;
-
-    if (trans == NULL)
-    {
-        LL_ERRS() << "No mKeyStringTranslator" << LL_ENDL;
-        return res;
-    }
 
-    // Append any masks
-#ifdef LL_DARWIN
-    // Standard Mac names for modifier keys in menu equivalents
-    // We could use the symbol characters, but they only exist in certain fonts.
-    if (accel_mask & MASK_CONTROL)
-    {
-        if (accel_mask & MASK_MAC_CONTROL)
-        {
-            res.append(trans("accel-mac-control"));
-        }
-        else
-        {
-            res.append(trans("accel-mac-command"));		// Symbol would be "\xE2\x8C\x98"
-        }
-    }
-    if (accel_mask & MASK_ALT)
-        res.append(trans("accel-mac-option"));		// Symbol would be "\xE2\x8C\xA5"
-    if (accel_mask & MASK_SHIFT)
-        res.append(trans("accel-mac-shift"));		// Symbol would be "\xE2\x8C\xA7"
-#else
-    if (accel_mask & MASK_CONTROL)
-        res.append(trans("accel-win-control"));
-    if (accel_mask & MASK_ALT)
-        res.append(trans("accel-win-alt"));
-    if (accel_mask & MASK_SHIFT)
-        res.append(trans("accel-win-shift"));
-#endif
-    return res;
-}
 //static
 std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key )
 {
@@ -403,7 +359,41 @@ std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key )
 		return res;
 	}
 	
-	res.append(stringFromAccelerator(accel_mask));
+	LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator;
+	
+	if( trans == NULL )
+	{
+		LL_ERRS() << "No mKeyStringTranslator" << LL_ENDL;
+		return res;
+	}
+	
+	// Append any masks
+#ifdef LL_DARWIN
+	// Standard Mac names for modifier keys in menu equivalents
+	// We could use the symbol characters, but they only exist in certain fonts.
+	if( accel_mask & MASK_CONTROL )
+	{
+		if ( accel_mask & MASK_MAC_CONTROL )
+		{
+			res.append( trans("accel-mac-control") );
+		}
+		else
+		{
+			res.append( trans("accel-mac-command") );		// Symbol would be "\xE2\x8C\x98"
+		}
+	}
+	if( accel_mask & MASK_ALT )
+		res.append( trans("accel-mac-option") );		// Symbol would be "\xE2\x8C\xA5"
+	if( accel_mask & MASK_SHIFT )
+		res.append( trans("accel-mac-shift") );		// Symbol would be "\xE2\x8C\xA7"
+#else
+	if( accel_mask & MASK_CONTROL )
+		res.append( trans("accel-win-control") );
+	if( accel_mask & MASK_ALT )
+		res.append( trans("accel-win-alt") );
+	if( accel_mask & MASK_SHIFT )
+		res.append( trans("accel-win-shift") );
+#endif
 	std::string key_string = LLKeyboard::stringFromKey(key);
 	if ((accel_mask & MASK_NORMALKEYS) &&
 		(key_string[0] == '-' || key_string[0] == '=' || key_string[0] == '+'))
diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h
index 36bd8bcbed..6f2dc87317 100644
--- a/indra/llwindow/llkeyboard.h
+++ b/indra/llwindow/llkeyboard.h
@@ -38,10 +38,10 @@ enum EKeystate
 {
 	KEYSTATE_DOWN,
 	KEYSTATE_LEVEL,
-	KEYSTATE_UP
+	KEYSTATE_UP 
 };
 
-typedef boost::function<bool(EKeystate keystate)> LLKeyFunc;
+typedef boost::function<void(EKeystate keystate)> LLKeyFunc;
 typedef std::string (LLKeyStringTranslatorFunc)(const char *label);
 	
 enum EKeyboardInsertMode
@@ -50,6 +50,15 @@ enum EKeyboardInsertMode
 	LL_KIM_OVERWRITE
 };
 
+class LLKeyBinding
+{
+public:
+	KEY				mKey;
+	MASK			mMask;
+// 	const char		*mName; // unused
+	LLKeyFunc		mFunction;
+};
+
 class LLWindowCallbacks;
 
 class LLKeyboard
@@ -94,8 +103,7 @@ public:
 
 	static BOOL		maskFromString(const std::string& str, MASK *mask);		// False on failure
 	static BOOL		keyFromString(const std::string& str, KEY *key);			// False on failure
-	static std::string stringFromKey(KEY key, bool translate = true);
-	static std::string stringFromAccelerator( MASK accel_mask ); // separated for convinience, returns with "+": "Shift+" or "Shift+Alt+"...
+	static std::string stringFromKey(KEY key);
 	static std::string stringFromAccelerator( MASK accel_mask, KEY key );
 
 	void setCallbacks(LLWindowCallbacks *cbs) { mCallbacks = cbs; }
diff --git a/indra/llwindow/llmousehandler.cpp b/indra/llwindow/llmousehandler.cpp
index e41ebd42f3..d5fa65fe4b 100644
--- a/indra/llwindow/llmousehandler.cpp
+++ b/indra/llwindow/llmousehandler.cpp
@@ -27,7 +27,7 @@
 #include "llmousehandler.h"
 
 //virtual
-BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down)
+BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down)
 {
 	BOOL handled = FALSE;
 	if (down)
diff --git a/indra/llwindow/llmousehandler.h b/indra/llwindow/llmousehandler.h
index d221dd117c..1dcd0348d8 100644
--- a/indra/llwindow/llmousehandler.h
+++ b/indra/llwindow/llmousehandler.h
@@ -29,7 +29,6 @@
 
 #include "linden_common.h"
 #include "llrect.h"
-#include "indra_constants.h"
 
 // Mostly-abstract interface.
 // Intended for use via multiple inheritance. 
@@ -47,7 +46,16 @@ public:
 		SHOW_ALWAYS,
 	} EShowToolTip;
 
-	virtual BOOL	handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down);
+	typedef enum {
+		CLICK_LEFT,
+		CLICK_MIDDLE,
+		CLICK_RIGHT,
+		CLICK_BUTTON4,
+		CLICK_BUTTON5,
+		CLICK_DOUBLELEFT
+	} EClickType;
+
+	virtual BOOL	handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down);
 	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask) = 0;
 	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask) = 0;
 	virtual BOOL	handleMiddleMouseDown(S32 x, S32 y, MASK mask) = 0;
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 00d19e3ba4..33fa186a2e 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -376,7 +376,6 @@ set(viewer_SOURCE_FILES
     llinventoryobserver.cpp
     llinventorypanel.cpp
     lljoystickbutton.cpp
-    llkeyconflict.cpp
     lllandmarkactions.cpp
     lllandmarklist.cpp
     lllegacyatmospherics.cpp
@@ -557,7 +556,6 @@ set(viewer_SOURCE_FILES
     llsecapi.cpp
     llsechandler_basic.cpp
     llselectmgr.cpp
-    llsetkeybinddialog.cpp
     llsettingspicker.cpp
     llsettingsvo.cpp
     llshareavatarhandler.cpp
@@ -663,7 +661,7 @@ set(viewer_SOURCE_FILES
     llviewerjointattachment.cpp
     llviewerjointmesh.cpp
     llviewerjoystick.cpp
-    llviewerinput.cpp
+    llviewerkeyboard.cpp
     llviewerlayer.cpp
     llviewermedia.cpp
     llviewermedia_streamingaudio.cpp
@@ -1009,7 +1007,6 @@ set(viewer_HEADER_FILES
     llinventoryobserver.h
     llinventorypanel.h
     lljoystickbutton.h
-    llkeyconflict.h
     lllandmarkactions.h
     lllandmarklist.h
     lllightconstants.h
@@ -1180,7 +1177,6 @@ set(viewer_HEADER_FILES
     llsecapi.h
     llsechandler_basic.h
     llselectmgr.h
-    llsetkeybinddialog.h
     llsettingspicker.h
     llsettingsvo.h
     llsidepanelappearance.h
@@ -1288,7 +1284,7 @@ set(viewer_HEADER_FILES
     llviewerjointattachment.h
     llviewerjointmesh.h
     llviewerjoystick.h
-    llviewerinput.h
+    llviewerkeyboard.h
     llviewerlayer.h
     llviewermedia.h
     llviewermediafocus.h
@@ -1669,7 +1665,7 @@ set(viewer_APPSETTINGS_FILES
     app_settings/grass.xml
     app_settings/high_graphics.xml
     app_settings/ignorable_dialogs.xml
-    app_settings/key_bindings.xml
+    app_settings/keys.xml
     app_settings/keywords_lsl_default.xml
     app_settings/logcontrol.xml
     app_settings/low_graphics.xml
diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml
deleted file mode 100644
index 4f6deb1f98..0000000000
--- a/indra/newview/app_settings/key_bindings.xml
+++ /dev/null
@@ -1,255 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<keys>
-  <first_person>
-    <binding key="A" mask="NONE" command="slide_left"/>
-    <binding key="D" mask="NONE" command="slide_right"/>
-    <binding key="W" mask="NONE" command="push_forward"/>
-    <binding key="S" mask="NONE" command="push_backward"/>
-    <binding key="E" mask="NONE" command="jump"/>
-    <binding key="C" mask="NONE" command="push_down"/>
-    <binding key="F" mask="NONE" command="toggle_fly"/>
-
-    <binding key="LEFT" mask="NONE" command="slide_left"/>
-    <binding key="RIGHT" mask="NONE" command="slide_right"/>
-    <binding key="UP" mask="NONE" command="push_forward"/>
-    <binding key="DOWN" mask="NONE" command="push_backward"/>
-    <binding key="PGUP" mask="NONE" command="jump"/>
-    <binding key="PGDN" mask="NONE" command="push_down"/>
-    <binding key="HOME" mask="NONE" command="toggle_fly"/>
-
-    <binding key="PAD_LEFT" mask="NONE" command="slide_left"/>
-    <binding key="PAD_RIGHT" mask="NONE" command="slide_right"/>
-    <binding key="PAD_UP" mask="NONE" command="push_forward"/>
-    <binding key="PAD_DOWN" mask="NONE" command="push_backward"/>
-    <binding key="PAD_PGUP" mask="NONE" command="jump"/>
-    <binding key="PAD_PGDN" mask="NONE" command="push_down"/>
-    <binding key="PAD_HOME" mask="NONE" command="toggle_fly"/>
-    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
-    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
-
-    <binding key="SPACE" mask="NONE" command="stop_moving"/>
-    <binding key="ENTER" mask="NONE" command="start_chat"/>
-    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
-
-    <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
-  </first_person>
-  <third_person>
-    <binding key="A" mask="NONE" command="turn_left"/>
-    <binding key="D" mask="NONE" command="turn_right"/>
-    <binding key="A" mask="SHIFT" command="slide_left"/>
-    <binding key="D" mask="SHIFT" command="slide_right"/>
-    <binding key="W" mask="NONE" command="push_forward"/>
-    <binding key="S" mask="NONE" command="push_backward"/>
-    <binding key="E" mask="NONE" command="jump"/>
-    <binding key="C" mask="NONE" command="push_down"/>
-
-    <binding key="F" mask="NONE" command="toggle_fly"/>
-
-    <binding key="SPACE" mask="NONE" command="stop_moving"/>
-    <binding key="ENTER" mask="NONE" command="start_chat"/>
-    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
-
-    <binding key="LEFT" mask="NONE" command="turn_left"/>
-    <binding key="LEFT" mask="SHIFT" command="slide_left"/>
-    <binding key="RIGHT" mask="NONE" command="turn_right"/>
-    <binding key="RIGHT" mask="SHIFT" command="slide_right"/>
-    <binding key="UP" mask="NONE" command="push_forward"/>
-    <binding key="DOWN" mask="NONE" command="push_backward"/>
-    <binding key="PGUP" mask="NONE" command="jump"/>
-    <binding key="PGDN" mask="NONE" command="push_down"/>
-    <binding key="HOME" mask="NONE" command="toggle_fly"/>
-
-    <binding key="PAD_LEFT" mask="NONE" command="turn_left"/>
-    <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
-    <binding key="PAD_RIGHT" mask="NONE" command="turn_right"/>
-    <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
-    <binding key="PAD_UP" mask="NONE" command="push_forward"/>
-    <binding key="PAD_DOWN" mask="NONE" command="push_backward"/>
-    <binding key="PAD_PGUP" mask="NONE" command="jump"/>
-    <binding key="PAD_PGDN" mask="NONE" command="push_down"/>
-    <binding key="PAD_HOME" mask="NONE" command="toggle_fly"/>
-    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
-    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
-
-    <!--Camera controls in third person on Alt-->
-    <binding key="LEFT" mask="ALT" command="spin_around_cw"/>
-    <binding key="RIGHT" mask="ALT" command="spin_around_ccw"/>
-    <binding key="UP" mask="ALT" command="move_forward"/>
-    <binding key="DOWN" mask="ALT" command="move_backward"/>
-    <binding key="PGUP" mask="ALT" command="spin_over"/>
-    <binding key="PGDN" mask="ALT" command="spin_under"/>
-
-    <binding key="A" mask="ALT" command="spin_around_cw"/>
-    <binding key="D" mask="ALT" command="spin_around_ccw"/>
-    <binding key="W" mask="ALT" command="move_forward"/>
-    <binding key="S" mask="ALT" command="move_backward"/>
-    <binding key="E" mask="ALT" command="spin_over"/>
-    <binding key="C" mask="ALT" command="spin_under"/>
-
-    <binding key="PAD_LEFT" mask="ALT" command="spin_around_cw"/>
-    <binding key="PAD_RIGHT" mask="ALT" command="spin_around_ccw"/>
-    <binding key="PAD_UP" mask="ALT" command="move_forward"/>
-    <binding key="PAD_DOWN" mask="ALT" command="move_backward"/>
-    <binding key="PAD_PGUP" mask="ALT" command="spin_over"/>
-    <binding key="PAD_PGDN" mask="ALT" command="spin_under"/>
-    <binding key="PAD_ENTER" mask="ALT" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/>
-
-    <!--mimic alt zoom behavior with keyboard only-->
-    <binding key="W" mask="CTL_ALT" command="spin_over"/>
-    <binding key="S" mask="CTL_ALT" command="spin_under"/>
-
-    <binding key="UP" mask="CTL_ALT" command="spin_over"/>
-    <binding key="DOWN" mask="CTL_ALT" command="spin_under"/>
-
-    <binding key="PAD_UP" mask="CTL_ALT" command="spin_over"/>
-    <binding key="PAD_DOWN" mask="CTL_ALT" command="spin_under"/>
-
-    <!--Therefore pan on Alt-Shift-->
-    <binding key="A" mask="CTL_ALT_SHIFT" command="pan_left"/>
-    <binding key="D" mask="CTL_ALT_SHIFT" command="pan_right"/>
-    <binding key="W" mask="CTL_ALT_SHIFT" command="pan_up"/>
-    <binding key="S" mask="CTL_ALT_SHIFT" command="pan_down"/>
-
-    <binding key="LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
-    <binding key="RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
-    <binding key="UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
-    <binding key="DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
-
-    <binding key="PAD_LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
-    <binding key="PAD_RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
-    <binding key="PAD_UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
-    <binding key="PAD_DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
-    <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>
-
-    <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
-    <binding key="" mask="NONE" mouse="LMB" command="walk_to"/>
-  </third_person>
-  <sitting>
-    <binding key="A" mask="ALT" command="spin_around_cw"/>
-    <binding key="D" mask="ALT" command="spin_around_ccw"/>
-    <binding key="W" mask="ALT" command="move_forward"/>
-    <binding key="S" mask="ALT" command="move_backward"/>
-    <binding key="E" mask="ALT" command="spin_over_sitting"/>
-    <binding key="C" mask="ALT" command="spin_under_sitting"/>
-
-    <binding key="LEFT" mask="ALT" command="spin_around_cw"/>
-    <binding key="RIGHT" mask="ALT" command="spin_around_ccw"/>
-    <binding key="UP" mask="ALT" command="move_forward"/>
-    <binding key="DOWN" mask="ALT" command="move_backward"/>
-    <binding key="PGUP" mask="ALT" command="spin_over"/>
-    <binding key="PGDN" mask="ALT" command="spin_under"/>
-
-    <binding key="W" mask="CTL_ALT" command="spin_over"/>
-    <binding key="S" mask="CTL_ALT" command="spin_under"/>
-    <binding key="E" mask="CTL_ALT" command="spin_over"/>
-    <binding key="C" mask="CTL_ALT" command="spin_under"/>
-
-    <binding key="UP" mask="CTL_ALT" command="spin_over"/>
-    <binding key="DOWN" mask="CTL_ALT" command="spin_under"/>
-    <binding key="PGUP" mask="CTL_ALT" command="spin_over"/>
-    <binding key="PGDN" mask="CTL_ALT" command="spin_under"/>
-
-
-    <binding key="A" mask="NONE" command="spin_around_cw_sitting"/>
-    <binding key="D" mask="NONE" command="spin_around_ccw_sitting"/>
-    <binding key="W" mask="NONE" command="move_forward_sitting"/>
-    <binding key="S" mask="NONE" command="move_backward_sitting"/>
-    <binding key="E" mask="NONE" command="spin_over_sitting"/>
-    <binding key="C" mask="NONE" command="spin_under_sitting"/>
-
-    <binding key="LEFT" mask="NONE" command="spin_around_cw_sitting"/>
-    <binding key="RIGHT" mask="NONE" command="spin_around_ccw_sitting"/>
-    <binding key="UP" mask="NONE" command="move_forward_sitting"/>
-    <binding key="DOWN" mask="NONE" command="move_backward_sitting"/>
-    <binding key="PGUP" mask="NONE" command="spin_over_sitting"/>
-    <binding key="PGDN" mask="NONE" command="spin_under_sitting"/>
-
-    <binding key="PAD_LEFT" mask="NONE" command="spin_around_cw_sitting"/>
-    <binding key="PAD_RIGHT" mask="NONE" command="spin_around_ccw_sitting"/>
-    <binding key="PAD_UP" mask="NONE" command="move_forward_sitting"/>
-    <binding key="PAD_DOWN" mask="NONE" command="move_backward_sitting"/>
-    <binding key="PAD_PGUP" mask="NONE" command="spin_over_sitting"/>
-    <binding key="PAD_PGDN" mask="NONE" command="spin_under_sitting"/>
-    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
-    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
-
-    <!--these are for passing controls when sitting on vehicles-->
-    <binding key="A" mask="SHIFT" command="slide_left"/>
-    <binding key="D" mask="SHIFT" command="slide_right"/>
-    <binding key="W" mask="SHIFT" command="move_forward_sitting"/>
-    <binding key="S" mask="SHIFT" command="move_backward_sitting"/>
-    <binding key="E" mask="SHIFT" command="spin_over_sitting"/>
-    <binding key="C" mask="SHIFT" command="spin_under_sitting"/>
-
-    <binding key="LEFT" mask="SHIFT" command="slide_left"/>
-    <binding key="RIGHT" mask="SHIFT" command="slide_right"/>
-    <binding key="UP" mask="SHIFT" command="move_forward_sitting"/>
-    <binding key="DOWN" mask="SHIFT" command="move_backward_sitting"/>
-    <binding key="PGUP" mask="SHIFT" command="spin_over_sitting"/>
-    <binding key="PGDN" mask="SHIFT" command="spin_under_sitting"/>
-
-    <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
-    <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
-    <binding key="PAD_UP" mask="SHIFT" command="move_forward_sitting"/>
-    <binding key="PAD_DOWN" mask="SHIFT" command="move_backward_sitting"/>
-    <binding key="PAD_PGUP" mask="SHIFT" command="spin_over_sitting"/>
-    <binding key="PAD_PGDN" mask="SHIFT" command="spin_under_sitting"/> 
-    <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/>
-
-    <!--pan on Alt-Shift-->
-    <binding key="A" mask="CTL_ALT_SHIFT" command="pan_left"/>
-    <binding key="D" mask="CTL_ALT_SHIFT" command="pan_right"/>
-    <binding key="W" mask="CTL_ALT_SHIFT" command="pan_up"/>
-    <binding key="S" mask="CTL_ALT_SHIFT" command="pan_down"/>
-
-    <binding key="LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
-    <binding key="RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
-    <binding key="UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
-    <binding key="DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
-
-    <binding key="PAD_LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
-    <binding key="PAD_RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
-    <binding key="PAD_UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
-    <binding key="PAD_DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
-    <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>
-
-    <binding key="ENTER" mask="NONE" command="start_chat"/>
-    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
-
-    <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
-  </sitting>
-  <edit_avatar>
-    <!--Avatar editing camera controls-->
-    <binding key="A" mask="NONE" command="edit_avatar_spin_cw"/>
-    <binding key="D" mask="NONE" command="edit_avatar_spin_ccw"/>
-    <binding key="W" mask="NONE" command="edit_avatar_move_forward"/>
-    <binding key="S" mask="NONE" command="edit_avatar_move_backward"/>
-    <binding key="E" mask="NONE" command="edit_avatar_spin_over"/>
-    <binding key="C" mask="NONE" command="edit_avatar_spin_under"/>
-    <binding key="LEFT" mask="NONE" command="edit_avatar_spin_cw"/>
-    <binding key="RIGHT" mask="NONE" command="edit_avatar_spin_ccw"/>
-    <binding key="UP" mask="NONE" command="edit_avatar_move_forward"/>
-    <binding key="DOWN" mask="NONE" command="edit_avatar_move_backward"/>
-    <binding key="PGUP" mask="NONE" command="edit_avatar_spin_over"/>
-    <binding key="PGDN" mask="NONE" command="edit_avatar_spin_under"/>
-    <binding key="ENTER" mask="NONE" command="start_chat"/>
-    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
-    <binding key="PAD_LEFT" mask="NONE" command="edit_avatar_spin_cw"/>
-    <binding key="PAD_RIGHT" mask="NONE" command="edit_avatar_spin_ccw"/>
-    <binding key="PAD_UP" mask="NONE" command="edit_avatar_move_forward"/>
-    <binding key="PAD_DOWN" mask="NONE" command="edit_avatar_move_backward"/>
-    <binding key="PAD_PGUP" mask="NONE" command="edit_avatar_spin_over"/>
-    <binding key="PAD_PGDN" mask="NONE" command="edit_avatar_spin_under"/>
-    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
-    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
-
-    <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/>
-  </edit_avatar>
-</keys>
diff --git a/indra/newview/app_settings/keys.xml b/indra/newview/app_settings/keys.xml
new file mode 100644
index 0000000000..a8037fec05
--- /dev/null
+++ b/indra/newview/app_settings/keys.xml
@@ -0,0 +1,363 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<keys>
+  <first_person>
+    <binding key="A" mask="NONE" command="slide_left"/>
+    <binding key="D" mask="NONE" command="slide_right"/>
+    <binding key="W" mask="NONE" command="push_forward"/>
+    <binding key="S" mask="NONE" command="push_backward"/>
+    <binding key="E" mask="NONE" command="jump"/>
+    <binding key="C" mask="NONE" command="push_down"/>
+    <binding key="F" mask="NONE" command="toggle_fly"/>
+
+    <binding key="LEFT" mask="NONE" command="slide_left"/>
+    <binding key="RIGHT" mask="NONE" command="slide_right"/>
+    <binding key="UP" mask="NONE" command="push_forward"/>
+    <binding key="DOWN" mask="NONE" command="push_backward"/>
+    <binding key="PGUP" mask="NONE" command="jump"/>
+    <binding key="PGDN" mask="NONE" command="push_down"/>
+    <binding key="HOME" mask="NONE" command="toggle_fly"/>
+
+    <binding key="PAD_LEFT" mask="NONE" command="slide_left"/>
+    <binding key="PAD_RIGHT" mask="NONE" command="slide_right"/>
+    <binding key="PAD_UP" mask="NONE" command="push_forward"/>
+    <binding key="PAD_DOWN" mask="NONE" command="push_backward"/>
+    <binding key="PAD_PGUP" mask="NONE" command="jump"/>
+    <binding key="PAD_PGDN" mask="NONE" command="push_down"/>
+    <binding key="PAD_HOME" mask="NONE" command="toggle_fly"/>
+    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
+    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+
+    <binding key="A" mask="SHIFT" command="slide_left"/>
+    <binding key="D" mask="SHIFT" command="slide_right"/>
+    <binding key="W" mask="SHIFT" command="push_forward"/>
+    <binding key="S" mask="SHIFT" command="push_backward"/>
+    <binding key="E" mask="SHIFT" command="jump"/>
+    <binding key="C" mask="SHIFT" command="push_down"/>
+    <binding key="F" mask="SHIFT" command="toggle_fly"/>
+
+    <binding key="SPACE" mask="NONE" command="stop_moving"/>
+    <binding key="ENTER" mask="NONE" command="start_chat"/>
+    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+
+    <binding key="LEFT" mask="SHIFT" command="slide_left"/>
+    <binding key="RIGHT" mask="SHIFT" command="slide_right"/>
+    <binding key="UP" mask="SHIFT" command="push_forward"/>
+    <binding key="DOWN" mask="SHIFT" command="push_backward"/>
+    <binding key="PGUP" mask="SHIFT" command="jump"/>
+    <binding key="PGDN" mask="SHIFT" command="push_down"/>
+
+    <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
+    <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
+    <binding key="PAD_UP" mask="SHIFT" command="push_forward"/>
+    <binding key="PAD_DOWN" mask="SHIFT" command="push_backward"/>
+    <binding key="PAD_PGUP" mask="SHIFT" command="jump"/>
+    <binding key="PAD_PGDN" mask="SHIFT" command="push_down"/>
+    <binding key="PAD_HOME" mask="SHIFT" command="toggle_fly"/>
+    <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/>
+  </first_person>
+  <third_person>
+    <binding key="A" mask="NONE" command="turn_left"/>
+    <binding key="D" mask="NONE" command="turn_right"/>
+    <binding key="A" mask="SHIFT" command="slide_left"/>
+    <binding key="D" mask="SHIFT" command="slide_right"/>
+    <binding key="W" mask="NONE" command="push_forward"/>
+    <binding key="S" mask="NONE" command="push_backward"/>
+    <binding key="W" mask="SHIFT" command="push_forward"/>
+    <binding key="S" mask="SHIFT" command="push_backward"/>
+    <binding key="E" mask="NONE" command="jump"/>
+    <binding key="C" mask="NONE" command="push_down"/>
+    <binding key="E" mask="SHIFT" command="jump"/>
+    <binding key="C" mask="SHIFT" command="push_down"/>
+
+    <binding key="F" mask="NONE" command="toggle_fly"/>
+    <binding key="F" mask="SHIFT" command="toggle_fly"/>
+
+    <binding key="SPACE" mask="NONE" command="stop_moving"/>
+    <binding key="ENTER" mask="NONE" command="start_chat"/>
+    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+
+    <binding key="LEFT" mask="NONE" command="turn_left"/>
+    <binding key="LEFT" mask="SHIFT" command="slide_left"/>
+    <binding key="RIGHT" mask="NONE" command="turn_right"/>
+    <binding key="RIGHT" mask="SHIFT" command="slide_right"/>
+    <binding key="UP" mask="NONE" command="push_forward"/>
+    <binding key="DOWN" mask="NONE" command="push_backward"/>
+    <binding key="UP" mask="SHIFT" command="push_forward"/>
+    <binding key="DOWN" mask="SHIFT" command="push_backward"/>
+    <binding key="PGUP" mask="NONE" command="jump"/>
+    <binding key="PGDN" mask="NONE" command="push_down"/>
+    <binding key="PGUP" mask="SHIFT" command="jump"/>
+    <binding key="PGDN" mask="SHIFT" command="push_down"/>
+    <binding key="HOME" mask="SHIFT" command="toggle_fly"/>
+    <binding key="HOME" mask="NONE" command="toggle_fly"/>
+
+    <binding key="PAD_LEFT" mask="NONE" command="turn_left"/>
+    <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
+    <binding key="PAD_RIGHT" mask="NONE" command="turn_right"/>
+    <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
+    <binding key="PAD_UP" mask="NONE" command="push_forward"/>
+    <binding key="PAD_DOWN" mask="NONE" command="push_backward"/>
+    <binding key="PAD_UP" mask="SHIFT" command="push_forward"/>
+    <binding key="PAD_DOWN" mask="SHIFT" command="push_backward"/>
+    <binding key="PAD_PGUP" mask="NONE" command="jump"/>
+    <binding key="PAD_PGDN" mask="NONE" command="push_down"/>
+    <binding key="PAD_PGUP" mask="SHIFT" command="jump"/>
+    <binding key="PAD_PGDN" mask="SHIFT" command="push_down"/>
+    <binding key="PAD_HOME" mask="NONE" command="toggle_fly"/>
+    <binding key="PAD_HOME" mask="SHIFT" command="toggle_fly"/>
+    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
+    <binding key="PAD_CENTER" mask="SHIFT" command="stop_moving"/>
+    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+    <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+    <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/>
+
+    <!--Camera controls in third person on Alt-->
+    <binding key="LEFT" mask="ALT" command="spin_around_cw"/>
+    <binding key="RIGHT" mask="ALT" command="spin_around_ccw"/>
+    <binding key="UP" mask="ALT" command="move_forward"/>
+    <binding key="DOWN" mask="ALT" command="move_backward"/>
+    <binding key="PGUP" mask="ALT" command="spin_over"/>
+    <binding key="PGDN" mask="ALT" command="spin_under"/>
+
+    <binding key="A" mask="ALT" command="spin_around_cw"/>
+    <binding key="D" mask="ALT" command="spin_around_ccw"/>
+    <binding key="W" mask="ALT" command="move_forward"/>
+    <binding key="S" mask="ALT" command="move_backward"/>
+    <binding key="E" mask="ALT" command="spin_over"/>
+    <binding key="C" mask="ALT" command="spin_under"/>
+
+    <binding key="PAD_LEFT" mask="ALT" command="spin_around_cw"/>
+    <binding key="PAD_RIGHT" mask="ALT" command="spin_around_ccw"/>
+    <binding key="PAD_UP" mask="ALT" command="move_forward"/>
+    <binding key="PAD_DOWN" mask="ALT" command="move_backward"/>
+    <binding key="PAD_PGUP" mask="ALT" command="spin_over"/>
+    <binding key="PAD_PGDN" mask="ALT" command="spin_under"/>
+    <binding key="PAD_ENTER" mask="ALT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/>
+
+    <!--mimic alt zoom behavior with keyboard only-->
+    <binding key="A" mask="CTL_ALT" command="spin_around_cw"/>
+    <binding key="D" mask="CTL_ALT" command="spin_around_ccw"/>
+    <binding key="W" mask="CTL_ALT" command="spin_over"/>
+    <binding key="S" mask="CTL_ALT" command="spin_under"/>
+    <binding key="E" mask="CTL_ALT" command="spin_over"/>
+    <binding key="C" mask="CTL_ALT" command="spin_under"/>
+
+    <binding key="LEFT" mask="CTL_ALT" command="spin_around_cw"/>
+    <binding key="RIGHT" mask="CTL_ALT" command="spin_around_ccw"/>
+    <binding key="UP" mask="CTL_ALT" command="spin_over"/>
+    <binding key="DOWN" mask="CTL_ALT" command="spin_under"/>
+    <binding key="PGUP" mask="CTL_ALT" command="spin_over"/>
+    <binding key="PGDN" mask="CTL_ALT" command="spin_under"/>
+
+    <binding key="PAD_LEFT" mask="CTL_ALT" command="spin_around_cw"/>
+    <binding key="PAD_RIGHT" mask="CTL_ALT" command="spin_around_ccw"/>
+    <binding key="PAD_UP" mask="CTL_ALT" command="spin_over"/>
+    <binding key="PAD_DOWN" mask="CTL_ALT" command="spin_under"/>
+    <binding key="PAD_PGUP" mask="CTL_ALT" command="spin_over"/>
+    <binding key="PAD_PGDN" mask="CTL_ALT" command="spin_under"/>
+    <binding key="PAD_ENTER" mask="CTL_ALT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="CTL_ALT" command="start_gesture"/>
+
+    <!--Therefore pan on Alt-Shift-->
+    <binding key="A" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="D" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="W" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="S" mask="CTL_ALT_SHIFT" command="pan_down"/>
+
+    <binding key="LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
+
+    <binding key="PAD_LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="PAD_RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="PAD_UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="PAD_DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
+    <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>
+  </third_person>
+
+  <!-- Basic editing camera control -->
+  <edit>
+    <binding key="A" mask="NONE" command="spin_around_cw"/>
+    <binding key="D" mask="NONE" command="spin_around_ccw"/>
+    <binding key="W" mask="NONE" command="move_forward"/>
+    <binding key="S" mask="NONE" command="move_backward"/>
+    <binding key="E" mask="NONE" command="spin_over"/>
+    <binding key="C" mask="NONE" command="spin_under"/>
+    <binding key="ENTER" mask="NONE" command="start_chat"/>
+    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+
+    <binding key="LEFT" mask="NONE" command="spin_around_cw"/>
+    <binding key="RIGHT" mask="NONE" command="spin_around_ccw"/>
+    <binding key="UP" mask="NONE" command="move_forward"/>
+    <binding key="DOWN" mask="NONE" command="move_backward"/>
+    <binding key="PGUP" mask="NONE" command="spin_over"/>
+    <binding key="PGDN" mask="NONE" command="spin_under"/>
+
+    <binding key="A" mask="SHIFT" command="pan_left"/>
+    <binding key="D" mask="SHIFT" command="pan_right"/>
+    <binding key="W" mask="SHIFT" command="pan_up"/>
+    <binding key="S" mask="SHIFT" command="pan_down"/>
+
+    <binding key="LEFT" mask="SHIFT" command="pan_left"/>
+    <binding key="RIGHT" mask="SHIFT" command="pan_right"/>
+    <binding key="UP" mask="SHIFT" command="pan_up"/>
+    <binding key="DOWN" mask="SHIFT" command="pan_down"/>
+
+    <!--Walking works with ALT held down.-->
+    <binding key="A" mask="ALT" command="slide_left"/>
+    <binding key="D" mask="ALT" command="slide_right"/>
+    <binding key="W" mask="ALT" command="push_forward"/>
+    <binding key="S" mask="ALT" command="push_backward"/>
+    <binding key="E" mask="ALT" command="jump"/>
+    <binding key="C" mask="ALT" command="push_down"/>
+
+    <binding key="LEFT" mask="ALT" command="slide_left"/>
+    <binding key="RIGHT" mask="ALT" command="slide_right"/>
+    <binding key="UP" mask="ALT" command="push_forward"/>
+    <binding key="DOWN" mask="ALT" command="push_backward"/>
+    <binding key="PGUP" mask="ALT" command="jump"/>
+    <binding key="PGDN" mask="ALT" command="push_down"/>
+    <binding key="HOME" mask="ALT" command="toggle_fly"/>
+
+    <binding key="PAD_LEFT" mask="ALT" command="slide_left"/>
+    <binding key="PAD_RIGHT" mask="ALT" command="slide_right"/>
+    <binding key="PAD_UP" mask="ALT" command="push_forward"/>
+    <binding key="PAD_DOWN" mask="ALT" command="push_backward"/>
+    <binding key="PAD_PGUP" mask="ALT" command="jump"/>
+    <binding key="PAD_PGDN" mask="ALT" command="push_down"/>
+    <binding key="PAD_ENTER" mask="ALT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/>
+  </edit>
+  <sitting>
+    <binding key="A" mask="ALT" command="spin_around_cw"/>
+    <binding key="D" mask="ALT" command="spin_around_ccw"/>
+    <binding key="W" mask="ALT" command="move_forward"/>
+    <binding key="S" mask="ALT" command="move_backward"/>
+    <binding key="E" mask="ALT" command="spin_over_sitting"/>
+    <binding key="C" mask="ALT" command="spin_under_sitting"/>
+
+    <binding key="LEFT" mask="ALT" command="spin_around_cw"/>
+    <binding key="RIGHT" mask="ALT" command="spin_around_ccw"/>
+    <binding key="UP" mask="ALT" command="move_forward"/>
+    <binding key="DOWN" mask="ALT" command="move_backward"/>
+    <binding key="PGUP" mask="ALT" command="spin_over"/>
+    <binding key="PGDN" mask="ALT" command="spin_under"/>
+
+    <binding key="A" mask="CTL_ALT" command="spin_around_cw"/>
+    <binding key="D" mask="CTL_ALT" command="spin_around_ccw"/>
+    <binding key="W" mask="CTL_ALT" command="spin_over"/>
+    <binding key="S" mask="CTL_ALT" command="spin_under"/>
+    <binding key="E" mask="CTL_ALT" command="spin_over"/>
+    <binding key="C" mask="CTL_ALT" command="spin_under"/>
+
+    <binding key="LEFT" mask="CTL_ALT" command="spin_around_cw"/>
+    <binding key="RIGHT" mask="CTL_ALT" command="spin_around_ccw"/>
+    <binding key="UP" mask="CTL_ALT" command="spin_over"/>
+    <binding key="DOWN" mask="CTL_ALT" command="spin_under"/>
+    <binding key="PGUP" mask="CTL_ALT" command="spin_over"/>
+    <binding key="PGDN" mask="CTL_ALT" command="spin_under"/>
+
+
+    <binding key="A" mask="NONE" command="spin_around_cw_sitting"/>
+    <binding key="D" mask="NONE" command="spin_around_ccw_sitting"/>
+    <binding key="W" mask="NONE" command="move_forward_sitting"/>
+    <binding key="S" mask="NONE" command="move_backward_sitting"/>
+    <binding key="E" mask="NONE" command="spin_over_sitting"/>
+    <binding key="C" mask="NONE" command="spin_under_sitting"/>
+
+    <binding key="LEFT" mask="NONE" command="spin_around_cw_sitting"/>
+    <binding key="RIGHT" mask="NONE" command="spin_around_ccw_sitting"/>
+    <binding key="UP" mask="NONE" command="move_forward_sitting"/>
+    <binding key="DOWN" mask="NONE" command="move_backward_sitting"/>
+    <binding key="PGUP" mask="NONE" command="spin_over_sitting"/>
+    <binding key="PGDN" mask="NONE" command="spin_under_sitting"/>
+
+    <binding key="PAD_LEFT" mask="NONE" command="spin_around_cw_sitting"/>
+    <binding key="PAD_RIGHT" mask="NONE" command="spin_around_ccw_sitting"/>
+    <binding key="PAD_UP" mask="NONE" command="move_forward_sitting"/>
+    <binding key="PAD_DOWN" mask="NONE" command="move_backward_sitting"/>
+    <binding key="PAD_PGUP" mask="NONE" command="spin_over_sitting"/>
+    <binding key="PAD_PGDN" mask="NONE" command="spin_under_sitting"/>
+    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
+    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+
+    <!--these are for passing controls when sitting on vehicles-->
+    <binding key="A" mask="SHIFT" command="slide_left"/>
+    <binding key="D" mask="SHIFT" command="slide_right"/>
+    <binding key="W" mask="SHIFT" command="move_forward_sitting"/>
+	<binding key="S" mask="SHIFT" command="move_backward_sitting"/>
+	<binding key="E" mask="SHIFT" command="spin_over_sitting"/>
+	<binding key="C" mask="SHIFT" command="spin_under_sitting"/>
+
+    <binding key="LEFT" mask="SHIFT" command="slide_left"/>
+    <binding key="RIGHT" mask="SHIFT" command="slide_right"/>
+    <binding key="UP" mask="SHIFT" command="move_forward_sitting"/>
+	<binding key="DOWN" mask="SHIFT" command="move_backward_sitting"/>
+	<binding key="PGUP" mask="SHIFT" command="spin_over_sitting"/>
+	<binding key="PGDN" mask="SHIFT" command="spin_under_sitting"/>
+
+    <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
+    <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
+    <binding key="PAD_UP" mask="SHIFT" command="move_forward_sitting"/>
+	<binding key="PAD_DOWN" mask="SHIFT" command="move_backward_sitting"/>
+	<binding key="PAD_PGUP" mask="SHIFT" command="spin_over_sitting"/>
+	<binding key="PAD_PGDN" mask="SHIFT" command="spin_under_sitting"/> 
+    <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/>
+
+    <!--pan on Alt-Shift-->
+    <binding key="A" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="D" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="W" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="S" mask="CTL_ALT_SHIFT" command="pan_down"/>
+
+    <binding key="LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
+
+    <binding key="PAD_LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="PAD_RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="PAD_UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="PAD_DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
+    <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>
+
+    <binding key="ENTER" mask="NONE" command="start_chat"/>
+    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+  </sitting>
+  <edit_avatar>
+    <!--Avatar editing camera controls-->
+    <binding key="A" mask="NONE" command="edit_avatar_spin_cw"/>
+    <binding key="D" mask="NONE" command="edit_avatar_spin_ccw"/>
+    <binding key="W" mask="NONE" command="edit_avatar_move_forward"/>
+    <binding key="S" mask="NONE" command="edit_avatar_move_backward"/>
+    <binding key="E" mask="NONE" command="edit_avatar_spin_over"/>
+    <binding key="C" mask="NONE" command="edit_avatar_spin_under"/>
+    <binding key="LEFT" mask="NONE" command="edit_avatar_spin_cw"/>
+    <binding key="RIGHT" mask="NONE" command="edit_avatar_spin_ccw"/>
+    <binding key="UP" mask="NONE" command="edit_avatar_move_forward"/>
+    <binding key="DOWN" mask="NONE" command="edit_avatar_move_backward"/>
+    <binding key="PGUP" mask="NONE" command="edit_avatar_spin_over"/>
+    <binding key="PGDN" mask="NONE" command="edit_avatar_spin_under"/>
+    <binding key="ENTER" mask="NONE" command="start_chat"/>
+    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+    <binding key="PAD_LEFT" mask="NONE" command="edit_avatar_spin_cw"/>
+    <binding key="PAD_RIGHT" mask="NONE" command="edit_avatar_spin_ccw"/>
+    <binding key="PAD_UP" mask="NONE" command="edit_avatar_move_forward"/>
+    <binding key="PAD_DOWN" mask="NONE" command="edit_avatar_move_backward"/>
+    <binding key="PAD_PGUP" mask="NONE" command="edit_avatar_spin_over"/>
+    <binding key="PAD_PGDN" mask="NONE" command="edit_avatar_spin_under"/>
+    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+  </edit_avatar>
+</keys>
\ No newline at end of file
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index b1606a0f3c..e8f01f7a60 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -3542,7 +3542,7 @@
     <key>DoubleClickAutoPilot</key>
     <map>
       <key>Comment</key>
-      <string>(Obsolete)Enable double-click auto pilot</string>
+      <string>Enable double-click auto pilot</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -3550,10 +3550,10 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    <key>DoubleClickTeleport</key> 
+    <key>DoubleClickTeleport</key>
     <map>
       <key>Comment</key>
-      <string>Enable double-click to teleport where allowed (afects minimap and people panel)</string>
+      <string>Enable double-click to teleport where allowed</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -8274,7 +8274,7 @@
     <key>PushToTalkButton</key>
     <map>
       <key>Comment</key>
-      <string>(Obsolete)Which button or keyboard key is used for push-to-talk</string>
+      <string>Which button or keyboard key is used for push-to-talk</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -15559,7 +15559,7 @@
     <key>ClickToWalk</key>
     <map>
       <key>Comment</key>
-      <string>(obsolete)Click in world to walk to location</string>
+      <string>Click in world to walk to location</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index f81f9557ff..59fc3500d9 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -49,7 +49,6 @@
 #include "llwindow.h"
 #include "llviewerstats.h"
 #include "llviewerstatsrecorder.h"
-#include "llkeyconflict.h" // for legacy keybinding support, remove later
 #include "llmarketplacefunctions.h"
 #include "llmarketplacenotifications.h"
 #include "llmd5.h"
@@ -150,7 +149,7 @@
 #include "llapr.h"
 #include <boost/lexical_cast.hpp>
 
-#include "llviewerinput.h"
+#include "llviewerkeyboard.h"
 #include "lllfsthread.h"
 #include "llworkerthread.h"
 #include "lltexturecache.h"
@@ -1003,113 +1002,20 @@ bool LLAppViewer::init()
 	gGLManager.getGLInfo(gDebugInfo);
 	gGLManager.printGLInfoString();
 
-	// Load User's bindings
-	std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml");
-#if 1
-    // Legacy support
-    // Remove #if-#endif section half a year after DRTVWR-501 releases.
-    // Mouse actions are part of keybinding file since DRTVWR-501 instead of being stored in
-    // settings.xml. To support legacy viewers that were storing in  settings.xml we need to
-    // transfer old variables to new format.
-    // Also part of backward compatibility is present in LLKeyConflictHandler to modify
-    // legacy variables on changes in new system (to make sure we won't enforce
-    // legacy values again if user dropped to defaults in new system)
-    if (LLVersionInfo::getChannelAndVersion() != gLastRunVersion
-        || !gDirUtilp->fileExists(key_bindings_file)) // if file is missing, assume that there were no changes by user yet
-    {
-        // copy mouse actions and voice key changes to new file
-        LL_INFOS("InitInfo") << "Converting legacy mouse bindings to new format" << LL_ENDL;
-        // Load settings from file
-        LLKeyConflictHandler third_person_view(LLKeyConflictHandler::MODE_THIRD_PERSON);
-
-        // Since we are only modifying keybindings if personal file doesn't exist yet,
-        // it should be safe to just overwrite the value
-        // If key is already in use somewhere by default, LLKeyConflictHandler should resolve it.
-        BOOL value = gSavedSettings.getBOOL("DoubleClickAutoPilot");
-        third_person_view.registerControl("walk_to",
-                                          0,
-                                          value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE,
-                                          KEY_NONE,
-                                          MASK_NONE,
-                                          value);
-
-        U32 index = value ? 1 : 0; // we can store multiple combinations per action, so if first is in use by doubleclick, go to second
-        value = gSavedSettings.getBOOL("ClickToWalk");
-        third_person_view.registerControl("walk_to",
-                                          index,
-                                          value ? EMouseClickType::CLICK_LEFT : EMouseClickType::CLICK_NONE,
-                                          KEY_NONE,
-                                          MASK_NONE,
-                                          value);
-
-        value = gSavedSettings.getBOOL("DoubleClickTeleport");
-        third_person_view.registerControl("teleport_to",
-                                          0,
-                                          value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE,
-                                          KEY_NONE,
-                                          MASK_NONE,
-                                          value);
-
-        std::string key_string = gSavedSettings.getString("PushToTalkButton");
-        EMouseClickType mouse = EMouseClickType::CLICK_NONE;
-        KEY key = KEY_NONE;
-        if (key_string == "MiddleMouse")
-        {
-            mouse = EMouseClickType::CLICK_MIDDLE;
-        }
-        else if (key_string == "MouseButton4")
-        {
-            mouse = EMouseClickType::CLICK_BUTTON4;
-        }
-        else if (key_string == "MouseButton5")
-        {
-            mouse = EMouseClickType::CLICK_BUTTON5;
-        }
-        else
-        {
-            LLKeyboard::keyFromString(key_string, &key);
-        }
-
-        value = gSavedSettings.getBOOL("PushToTalkToggle");
-        std::string control_name = value ? "toggle_voice" : "voice_follow_key";
-        third_person_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true);
-
-        if (third_person_view.hasUnsavedChanges())
-        {
-            // calls loadBindingsXML()
-            third_person_view.saveToSettings();
-        }
-
-        // in case of voice we need to repeat this in other modes (teleports and
-        // autopilot are not entirely practical when sitting or editing)
-
-        for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
-        {
-            if (i != LLKeyConflictHandler::MODE_THIRD_PERSON)
-            {
-                LLKeyConflictHandler handler((LLKeyConflictHandler::ESourceMode)i);
+	// Load Default bindings
+	std::string key_bindings_file = gDirUtilp->findFile("keys.xml",
+														gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
+														gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
 
-                handler.registerControl(control_name, 0, mouse, key, MASK_NONE, true);
 
-                if (handler.hasUnsavedChanges())
-                {
-                    // calls loadBindingsXML()
-                    handler.saveToSettings();
-                }
-            }
-        }
-    }
-    // since something might have gone wrong or there might have been nothing to save
-    // (and because otherwise following code will have to be encased in else{}),
-    // load everything one last time
-#endif
-	if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file))
+	if (!gViewerKeyboard.loadBindingsXML(key_bindings_file))
 	{
-		// Failed to load custom bindings, try default ones
-		key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "key_bindings.xml");
-		if (!gViewerInput.loadBindingsXML(key_bindings_file))
+		std::string key_bindings_file = gDirUtilp->findFile("keys.ini",
+															gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
+															gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
+		if (!gViewerKeyboard.loadBindings(key_bindings_file))
 		{
-			LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL;
+			LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL;
 		}
 	}
 
@@ -1544,7 +1450,6 @@ bool LLAppViewer::doFrame()
 			{
 				joystick->scanJoystick();
 				gKeyboard->scanKeyboard();
-                gViewerInput.scanMouse();
 			}
 
 			// Update state based on messages, user input, object idle.
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 91a3ae384d..81f4b2234c 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -71,9 +71,8 @@
 #include "lltrans.h"
 #include "llviewercontrol.h"
 #include "llviewercamera.h"
-#include "llviewereventrecorder.h"
-#include "llviewermessage.h"
 #include "llviewerwindow.h"
+#include "llviewermessage.h"
 #include "llviewershadermgr.h"
 #include "llviewerthrottle.h"
 #include "llvoavatarself.h"
@@ -160,6 +159,87 @@ struct LabelTable : public LLInitParam::Block<LabelTable>
     {}
 };
 
+class LLVoiceSetKeyDialog : public LLModalDialog
+{
+public:
+	LLVoiceSetKeyDialog(const LLSD& key);
+	~LLVoiceSetKeyDialog();
+	
+	/*virtual*/ BOOL postBuild();
+	
+	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);
+	static void onCancel(void* user_data);
+		
+private:
+	LLFloaterPreference* mParent;
+};
+
+LLVoiceSetKeyDialog::LLVoiceSetKeyDialog(const LLSD& key)
+  : LLModalDialog(key),
+	mParent(NULL)
+{
+}
+
+//virtual
+BOOL LLVoiceSetKeyDialog::postBuild()
+{
+	childSetAction("Cancel", onCancel, this);
+	getChild<LLUICtrl>("Cancel")->setFocus(TRUE);
+	
+	gFocusMgr.setKeystrokesOnly(TRUE);
+	
+	return TRUE;
+}
+
+LLVoiceSetKeyDialog::~LLVoiceSetKeyDialog()
+{
+}
+
+BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask)
+{
+	BOOL result = TRUE;
+	
+	if (key == 'Q' && mask == MASK_CONTROL)
+	{
+		result = FALSE;
+	}
+	else if (mParent)
+	{
+		mParent->setKey(key);
+	}
+	closeFloater();
+	return result;
+}
+
+BOOL LLVoiceSetKeyDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down)
+{
+    BOOL result = FALSE;
+    if (down
+        && (clicktype == LLMouseHandler::CLICK_MIDDLE || clicktype == LLMouseHandler::CLICK_BUTTON4 || clicktype == LLMouseHandler::CLICK_BUTTON5)
+        && mask == 0)
+    {
+        mParent->setMouse(clicktype);
+        result = TRUE;
+        closeFloater();
+    }
+    else
+    {
+        result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down);
+    }
+
+    return result;
+}
+
+//static
+void LLVoiceSetKeyDialog::onCancel(void* user_data)
+{
+	LLVoiceSetKeyDialog* self = (LLVoiceSetKeyDialog*)user_data;
+	self->closeFloater();
+}
+
 
 // global functions 
 
@@ -239,6 +319,37 @@ 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;
@@ -263,7 +374,8 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
 	mGotPersonalInfo(false),
 	mOriginalIMViaEmail(false),
 	mLanguageChanged(false),
-	mAvatarDataInitialized(false)
+	mAvatarDataInitialized(false),
+	mClickActionDirty(false)
 {
 	LLConversationLog::instance().addObserver(this);
 
@@ -272,7 +384,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
 	static bool registered_dialog = false;
 	if (!registered_dialog)
 	{
-		LLFloaterReg::add("keybind_dialog", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLSetKeyBindDialog>);
+		LLFloaterReg::add("voice_set_key", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLVoiceSetKeyDialog>);
 		registered_dialog = true;
 	}
 	
@@ -285,6 +397,8 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
 	mCommitCallbackRegistrar.add("Pref.ResetCache",				boost::bind(&LLFloaterPreference::onClickResetCache, this));
 	mCommitCallbackRegistrar.add("Pref.ClickSkin",				boost::bind(&LLFloaterPreference::onClickSkin, this,_1, _2));
 	mCommitCallbackRegistrar.add("Pref.SelectSkin",				boost::bind(&LLFloaterPreference::onSelectSkin, this));
+	mCommitCallbackRegistrar.add("Pref.VoiceSetKey",			boost::bind(&LLFloaterPreference::onClickSetKey, this));
+	mCommitCallbackRegistrar.add("Pref.VoiceSetMiddleMouse",	boost::bind(&LLFloaterPreference::onClickSetMiddleMouse, this));
 	mCommitCallbackRegistrar.add("Pref.SetSounds",				boost::bind(&LLFloaterPreference::onClickSetSounds, this));
 	mCommitCallbackRegistrar.add("Pref.ClickEnablePopup",		boost::bind(&LLFloaterPreference::onClickEnablePopup, this));
 	mCommitCallbackRegistrar.add("Pref.ClickDisablePopup",		boost::bind(&LLFloaterPreference::onClickDisablePopup, this));	
@@ -579,6 +693,12 @@ void LLFloaterPreference::apply()
 	}
 
 	saveAvatarProperties();
+
+	if (mClickActionDirty)
+	{
+		updateClickActionSettings();
+		mClickActionDirty = false;
+	}
 }
 
 void LLFloaterPreference::cancel()
@@ -611,7 +731,11 @@ void LLFloaterPreference::cancel()
 	// reverts any changes to current skin
 	gSavedSettings.setString("SkinCurrent", sSkin);
 
-	updateClickActionViews();
+	if (mClickActionDirty)
+	{
+		updateClickActionControls();
+		mClickActionDirty = false;
+	}
 
 	LLFloaterPreferenceProxy * advanced_proxy_settings = LLFloaterReg::findTypedInstance<LLFloaterPreferenceProxy>("prefs_proxy");
 	if (advanced_proxy_settings)
@@ -696,7 +820,7 @@ void LLFloaterPreference::onOpen(const LLSD& key)
 	onChangeAnimationFolder();
 
 	// Load (double-)click to walk/teleport settings.
-	updateClickActionViews();
+	updateClickActionControls();
 	
 	// Enabled/disabled popups, might have been changed by user actions
 	// while preferences floater was closed.
@@ -1493,7 +1617,6 @@ void LLFloaterPreference::refresh()
 	{
 		advanced->refresh();
 	}
-    updateClickActionViews();
 }
 
 void LLFloaterPreferenceGraphicsAdvanced::refresh()
@@ -1535,6 +1658,72 @@ void LLFloaterPreference::onChangeQuality(const LLSD& data)
 	refresh();
 }
 
+void LLFloaterPreference::onClickSetKey()
+{
+	LLVoiceSetKeyDialog* dialog = LLFloaterReg::showTypedInstance<LLVoiceSetKeyDialog>("voice_set_key", LLSD(), TRUE);
+	if (dialog)
+	{
+		dialog->setParent(this);
+	}
+}
+
+void LLFloaterPreference::setKey(KEY key)
+{
+	getChild<LLUICtrl>("modifier_combo")->setValue(LLKeyboard::stringFromKey(key));
+	// update the control right away since we no longer wait for apply
+	getChild<LLUICtrl>("modifier_combo")->onCommit();
+}
+
+void LLFloaterPreference::setMouse(LLMouseHandler::EClickType click)
+{
+    std::string bt_name;
+    std::string ctrl_value;
+    switch (click)
+    {
+        case LLMouseHandler::CLICK_MIDDLE:
+            bt_name = "middle_mouse";
+            ctrl_value = MIDDLE_MOUSE_CV;
+            break;
+        case LLMouseHandler::CLICK_BUTTON4:
+            bt_name = "button4_mouse";
+            ctrl_value = MOUSE_BUTTON_4_CV;
+            break;
+        case LLMouseHandler::CLICK_BUTTON5:
+            bt_name = "button5_mouse";
+            ctrl_value = MOUSE_BUTTON_5_CV;
+            break;
+        default:
+            break;
+    }
+
+    if (!ctrl_value.empty())
+    {
+        LLUICtrl* p2t_line_editor = getChild<LLUICtrl>("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<LLPanel*>(p2t_line_editor->getParent());
+        if (advanced_preferences)
+        {
+            p2t_line_editor->setValue(advanced_preferences->getString(bt_name));
+        }
+    }
+}
+
+void LLFloaterPreference::onClickSetMiddleMouse()
+{
+	LLUICtrl* p2t_line_editor = getChild<LLUICtrl>("modifier_combo");
+
+	// update the control right away since we no longer wait for apply
+	p2t_line_editor->setControlValue(MIDDLE_MOUSE_CV);
+
+	//push2talk button "middle mouse" control value is in English, need to localize it for presentation
+	LLPanel* advanced_preferences = dynamic_cast<LLPanel*>(p2t_line_editor->getParent());
+	if (advanced_preferences)
+	{
+		p2t_line_editor->setValue(advanced_preferences->getString("middle_mouse"));
+	}
+}
+
 void LLFloaterPreference::onClickSetSounds()
 {
 	// Disable Enable gesture sounds checkbox if the master sound is disabled 
@@ -1542,6 +1731,18 @@ void LLFloaterPreference::onClickSetSounds()
 	getChild<LLCheckBoxCtrl>("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<LLScrollListCtrl>("disabled_popups");
@@ -2005,7 +2206,7 @@ void LLFloaterPreference::onClickAdvanced()
 
 void LLFloaterPreference::onClickActionChange()
 {
-    updateClickActionControls();
+	mClickActionDirty = true;
 }
 
 void LLFloaterPreference::onClickPermsDefault()
@@ -2045,81 +2246,21 @@ void LLFloaterPreference::onLogChatHistorySaved()
 	}
 }
 
-void LLFloaterPreference::updateClickActionControls()
+void LLFloaterPreference::updateClickActionSettings()
 {
-    const int single_clk_action = getChild<LLComboBox>("single_click_action_combo")->getValue().asInteger();
-    const int double_clk_action = getChild<LLComboBox>("double_click_action_combo")->getValue().asInteger();
-
-    // Todo: This is a very ugly way to get access to keybindings.
-    // Reconsider possible options.
-    // Potential option: make constructor of LLKeyConflictHandler private
-    // but add a getter that will return shared pointer for specific
-    // mode, pointer should only exist so long as there are external users.
-    // In such case we won't need to do this 'dynamic_cast' nightmare.
-    // updateTable() can also be avoided
-    LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
-    for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin();
-        iter != tabcontainer->getChildList()->end(); ++iter)
-    {
-        LLView* view = *iter;
-        LLPanelPreferenceControls* panel = dynamic_cast<LLPanelPreferenceControls*>(view);
-        if (panel)
-        {
-            panel->setKeyBind("walk_to",
-                              EMouseClickType::CLICK_LEFT,
-                              KEY_NONE,
-                              MASK_NONE,
-                              single_clk_action == 1);
-            
-            panel->setKeyBind("walk_to",
-                              EMouseClickType::CLICK_DOUBLELEFT,
-                              KEY_NONE,
-                              MASK_NONE,
-                              double_clk_action == 1);
-            
-            panel->setKeyBind("teleport_to",
-                              EMouseClickType::CLICK_DOUBLELEFT,
-                              KEY_NONE,
-                              MASK_NONE,
-                              double_clk_action == 2);
-
-            panel->updateAndApply();
-        }
-    }
+	const int single_clk_action = getChild<LLComboBox>("single_click_action_combo")->getValue().asInteger();
+	const int double_clk_action = getChild<LLComboBox>("double_click_action_combo")->getValue().asInteger();
+
+	gSavedSettings.setBOOL("ClickToWalk",			single_clk_action == 1);
+	gSavedSettings.setBOOL("DoubleClickAutoPilot",	double_clk_action == 1);
+	gSavedSettings.setBOOL("DoubleClickTeleport",	double_clk_action == 2);
 }
 
-void LLFloaterPreference::updateClickActionViews()
+void LLFloaterPreference::updateClickActionControls()
 {
-    bool click_to_walk = false;
-    bool dbl_click_to_walk = false;
-    bool dbl_click_to_teleport = false;
-
-    // Todo: This is a very ugly way to get access to keybindings.
-    // Reconsider possible options.
-    LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
-    for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin();
-        iter != tabcontainer->getChildList()->end(); ++iter)
-    {
-        LLView* view = *iter;
-        LLPanelPreferenceControls* panel = dynamic_cast<LLPanelPreferenceControls*>(view);
-        if (panel)
-        {
-            click_to_walk = panel->canKeyBindHandle("walk_to",
-                EMouseClickType::CLICK_LEFT,
-                KEY_NONE,
-                MASK_NONE);
-
-            dbl_click_to_walk = panel->canKeyBindHandle("walk_to",
-                EMouseClickType::CLICK_DOUBLELEFT,
-                KEY_NONE,
-                MASK_NONE);
-
-            dbl_click_to_teleport = panel->canKeyBindHandle("teleport_to",
-                EMouseClickType::CLICK_DOUBLELEFT,
-                KEY_NONE,
-                MASK_NONE);
-        }
-    }
+	const bool click_to_walk = gSavedSettings.getBOOL("ClickToWalk");
+	const bool dbl_click_to_walk = gSavedSettings.getBOOL("DoubleClickAutoPilot");
+	const bool dbl_click_to_teleport = gSavedSettings.getBOOL("DoubleClickTeleport");
 
 	getChild<LLComboBox>("single_click_action_combo")->setValue((int)click_to_walk);
 	getChild<LLComboBox>("double_click_action_combo")->setValue(dbl_click_to_teleport ? 2 : (int)dbl_click_to_walk);
@@ -2306,6 +2447,25 @@ BOOL LLPanelPreference::postBuild()
 		getChild<LLTextBox>("mute_chb_label")->setClickedCallback(boost::bind(&toggleMuteWhenMinimized));
 	}
 
+	//////////////////////PanelAdvanced ///////////////////
+	if (hasChild("modifier_combo", TRUE))
+	{
+		//localizing if push2talk button is set to middle mouse
+		std::string modifier_value = getChild<LLUICtrl>("modifier_combo")->getValue().asString();
+		if (MIDDLE_MOUSE_CV == modifier_value)
+		{
+			getChild<LLUICtrl>("modifier_combo")->setValue(getString("middle_mouse"));
+		}
+		else if (MOUSE_BUTTON_4_CV == modifier_value)
+		{
+			getChild<LLUICtrl>("modifier_combo")->setValue(getString("button4_mouse"));
+		}
+		else if (MOUSE_BUTTON_5_CV == modifier_value)
+		{
+			getChild<LLUICtrl>("modifier_combo")->setValue(getString("button5_mouse"));
+		}
+	}
+
 	//////////////////////PanelSetup ///////////////////
 	if (hasChild("max_bandwidth"), TRUE)
 	{
@@ -2583,7 +2743,7 @@ void LLPanelPreferenceGraphics::setPresetText()
 		}
 	}
 
-    if (hasDirtyChilds() && !preset_graphic_active.empty())
+	if (hasDirtyChilds() && !preset_graphic_active.empty())
 	{
 		gSavedSettings.setString("PresetGraphicActive", "");
 		preset_graphic_active.clear();
@@ -2703,560 +2863,6 @@ void LLPanelPreferenceGraphics::setHardwareDefaults()
 	resetDirtyChilds();
 }
 
-//------------------------LLPanelPreferenceControls--------------------------------
-static LLPanelInjector<LLPanelPreferenceControls> t_pref_contrls("panel_preference_controls");
-
-LLPanelPreferenceControls::LLPanelPreferenceControls()
-    :LLPanelPreference(),
-    mEditingColumn(-1),
-    mEditingMode(0)
-{
-    // MODE_COUNT - 1 because there are currently no settings assigned to 'saved settings'.
-    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
-    {
-        mConflictHandler[i].setLoadMode((LLKeyConflictHandler::ESourceMode)i);
-    }
-}
-
-LLPanelPreferenceControls::~LLPanelPreferenceControls()
-{
-}
-
-BOOL LLPanelPreferenceControls::postBuild()
-{
-    // populate list of controls
-    pControlsTable = getChild<LLScrollListCtrl>("controls_list");
-    pKeyModeBox = getChild<LLComboBox>("key_mode");
-
-    pControlsTable->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onListCommit, this));
-    pKeyModeBox->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onModeCommit, this));
-    getChild<LLButton>("restore_defaults")->setCommitCallback(boost::bind(&LLPanelPreferenceControls::onRestoreDefaultsBtn, this));
-
-    return TRUE;
-}
-
-void LLPanelPreferenceControls::regenerateControls()
-{
-    mEditingMode = pKeyModeBox->getValue().asInteger();
-    mConflictHandler[mEditingMode].loadFromSettings((LLKeyConflictHandler::ESourceMode)mEditingMode);
-    populateControlTable();
-}
-
-bool LLPanelPreferenceControls::addControlTableColumns(const std::string &filename)
-{
-    LLXMLNodePtr xmlNode;
-    LLScrollListCtrl::Contents contents;
-    if (!LLUICtrlFactory::getLayeredXMLNode(filename, xmlNode))
-    {
-        LL_WARNS() << "Failed to load " << filename << LL_ENDL;
-        return false;
-    }
-    LLXUIParser parser;
-    parser.readXUI(xmlNode, contents, filename);
-
-    if (!contents.validateBlock())
-    {
-        return false;
-    }
-
-    for (LLInitParam::ParamIterator<LLScrollListColumn::Params>::const_iterator col_it = contents.columns.begin();
-        col_it != contents.columns.end();
-        ++col_it)
-    {
-        pControlsTable->addColumn(*col_it);
-    }
-
-    return true;
-}
-
-bool LLPanelPreferenceControls::addControlTableRows(const std::string &filename)
-{
-    LLXMLNodePtr xmlNode;
-    LLScrollListCtrl::Contents contents;
-    if (!LLUICtrlFactory::getLayeredXMLNode(filename, xmlNode))
-    {
-        LL_WARNS() << "Failed to load " << filename << LL_ENDL;
-        return false;
-    }
-    LLXUIParser parser;
-    parser.readXUI(xmlNode, contents, filename);
-
-    if (!contents.validateBlock())
-    {
-        return false;
-    }
-
-    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 = "";
-
-
-    for (LLInitParam::ParamIterator<LLScrollListItem::Params>::const_iterator row_it = contents.rows.begin();
-        row_it != contents.rows.end();
-        ++row_it)
-    {
-        std::string control = row_it->value.getValue().asString();
-        if (!control.empty() && control != "menu_separator")
-        {
-            // At the moment viewer is hardcoded to assume that there are 4 collumns
-            LLScrollListItem::Params item_params(*row_it);
-            bool enabled = mConflictHandler[mEditingMode].canAssignControl(control);
-            item_params.enabled.setValue(enabled);
-            cell_params.column = "lst_ctrl1";
-            cell_params.value = mConflictHandler[mEditingMode].getControlString(control, 0);
-            item_params.columns.add(cell_params);
-            cell_params.column = "lst_ctrl2";
-            cell_params.value = mConflictHandler[mEditingMode].getControlString(control, 1);
-            item_params.columns.add(cell_params);
-            cell_params.column = "lst_ctrl3";
-            cell_params.value = mConflictHandler[mEditingMode].getControlString(control, 2);
-            item_params.columns.add(cell_params);
-            pControlsTable->addRow(item_params, EAddPosition::ADD_BOTTOM);
-        }
-        else
-        {
-            // Separator example:
-            // <rows
-            //  enabled = "false">
-            //  <columns
-            //   type = "icon"
-            //   color = "0 0 0 0.7"
-            //   halign = "center"
-            //   value = "menu_separator" />
-            //</rows>
-            pControlsTable->addRow(*row_it, EAddPosition::ADD_BOTTOM);
-        }
-    }
-    return true;
-}
-
-void LLPanelPreferenceControls::addControlTableSeparator()
-{
-    pControlsTable->addSeparator(EAddPosition::ADD_BOTTOM);
-}
-
-void LLPanelPreferenceControls::populateControlTable()
-{
-    pControlsTable->clearRows();
-    pControlsTable->clearColumns();
-
-    // add columns
-    std::string filename;
-    switch ((LLKeyConflictHandler::ESourceMode)mEditingMode)
-    {
-    case LLKeyConflictHandler::MODE_THIRD_PERSON:
-    case LLKeyConflictHandler::MODE_FIRST_PERSON:
-    case LLKeyConflictHandler::MODE_EDIT_AVATAR:
-    case LLKeyConflictHandler::MODE_SITTING:
-        filename = "control_table_contents_columns_basic.xml";
-        break;
-    default:
-        // Either unknown mode or MODE_SAVED_SETTINGS
-        // It doesn't have UI or actual settings yet
-        LL_INFOS() << "Unimplemented mode" << LL_ENDL;
-        return;
-    }
-    addControlTableColumns(filename);
-
-
-    if (mEditingMode == LLKeyConflictHandler::MODE_FIRST_PERSON)
-    {
-        addControlTableRows("control_table_contents_movement.xml");
-        addControlTableSeparator();
-        addControlTableRows("control_table_contents_media.xml");
-    }
-    // MODE_THIRD_PERSON; MODE_EDIT_AVATAR; MODE_SITTING
-    else if (mEditingMode < LLKeyConflictHandler::MODE_SAVED_SETTINGS)
-    {
-        // In case of 'sitting' mode, movements still apply due to vehicles
-        addControlTableRows("control_table_contents_movement.xml");
-        addControlTableSeparator();
-
-        addControlTableRows("control_table_contents_camera.xml");
-        if (mEditingMode == LLKeyConflictHandler::MODE_SITTING)
-        {
-            addControlTableRows("control_table_contents_camera_sitting.xml");
-        }
-        addControlTableSeparator();
-
-        addControlTableRows("control_table_contents_editing.xml");
-        addControlTableSeparator();
-
-        addControlTableRows("control_table_contents_media.xml");
-    }
-    else
-    {
-        LL_INFOS() << "Unimplemented mode" << LL_ENDL;
-        return;
-    }
-}
-
-void LLPanelPreferenceControls::updateTable()
-{
-    mEditingControl.clear();
-    std::vector<LLScrollListItem*> list = pControlsTable->getAllData();
-    for (S32 i = 0; i < list.size(); ++i)
-    {
-        std::string control = list[i]->getValue();
-        if (!control.empty())
-        {
-            LLScrollListCell* cell = list[i]->getColumn(1);
-            cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 0));
-            cell = list[i]->getColumn(2);
-            cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 1));
-            cell = list[i]->getColumn(3);
-            cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 2));
-        }
-    }
-    pControlsTable->deselectAllItems();
-}
-
-void LLPanelPreferenceControls::apply()
-{
-    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
-    {
-        if (mConflictHandler[i].hasUnsavedChanges())
-        {
-            mConflictHandler[i].saveToSettings();
-        }
-    }
-}
-
-void LLPanelPreferenceControls::cancel()
-{
-    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
-    {
-        if (mConflictHandler[i].hasUnsavedChanges())
-        {
-            mConflictHandler[i].clear();
-        }
-    }
-    pControlsTable->clearRows();
-    pControlsTable->clearColumns();
-}
-
-void LLPanelPreferenceControls::saveSettings()
-{
-    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
-    {
-        if (mConflictHandler[i].hasUnsavedChanges())
-        {
-            mConflictHandler[i].saveToSettings();
-            mConflictHandler[i].clear();
-        }
-    }
-
-    S32 mode = pKeyModeBox->getValue().asInteger();
-    if (mConflictHandler[mode].empty() || pControlsTable->isEmpty())
-    {
-        regenerateControls();
-    }
-}
-
-void LLPanelPreferenceControls::resetDirtyChilds()
-{
-    regenerateControls();
-}
-
-void LLPanelPreferenceControls::onListCommit()
-{
-    LLScrollListItem* item = pControlsTable->getFirstSelected();
-    if (item == NULL)
-    {
-        return;
-    }
-
-    std::string control = item->getValue();
-
-    if (control.empty())
-    {
-        pControlsTable->deselectAllItems();
-        return;
-    }
-
-    if (!mConflictHandler[mEditingMode].canAssignControl(control))
-    {
-        pControlsTable->deselectAllItems();
-        return;
-    }
-
-    S32 cell_ind = item->getSelectedCell();
-    if (cell_ind <= 0)
-    {
-        pControlsTable->deselectAllItems();
-        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
-
-    LLScrollListCell* cell = item->getColumn(cell_ind);
-    if (cell)
-    {
-        LLSetKeyBindDialog* dialog = LLFloaterReg::getTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD());
-        if (dialog)
-        {
-            mEditingControl = control;
-            mEditingColumn = cell_ind;
-            dialog->setParent(this, pControlsTable, DEFAULT_KEY_FILTER);
-
-            LLFloater* root_floater = gFloaterView->getParentFloater(this);
-            if (root_floater)
-                root_floater->addDependentFloater(dialog);
-            dialog->openFloater();
-            dialog->setFocus(TRUE);
-        }
-    }
-    else
-    {
-        pControlsTable->deselectAllItems();
-    }
-}
-
-void LLPanelPreferenceControls::onModeCommit()
-{
-    mEditingMode = pKeyModeBox->getValue().asInteger();
-    if (mConflictHandler[mEditingMode].empty())
-    {
-        // opening for first time
-        mConflictHandler[mEditingMode].loadFromSettings((LLKeyConflictHandler::ESourceMode)mEditingMode);
-    }
-    populateControlTable();
-}
-
-void LLPanelPreferenceControls::onRestoreDefaultsBtn()
-{
-    LLNotificationsUtil::add("PreferenceControlsDefaults", LLSD(), LLSD(), boost::bind(&LLPanelPreferenceControls::onRestoreDefaultsResponse, this, _1, _2));
-}
-
-void LLPanelPreferenceControls::onRestoreDefaultsResponse(const LLSD& notification, const LLSD& response)
-{
-    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
-    switch(option)
-    {
-    case 0: // All
-        for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
-        {
-            mConflictHandler[i].resetToDefaults();
-            // Apply changes to viewer as 'temporary'
-            mConflictHandler[i].saveToSettings(true);
-
-            // notify comboboxes in move&view about potential change
-            LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
-            if (instance)
-            {
-                instance->updateClickActionViews();
-            }
-        }
-
-        updateTable();
-        break;
-    case 1: // Current
-        mConflictHandler[mEditingMode].resetToDefaults();
-        // Apply changes to viewer as 'temporary'
-        mConflictHandler[mEditingMode].saveToSettings(true);
-
-        if (mEditingMode == LLKeyConflictHandler::MODE_THIRD_PERSON)
-        {
-            // notify comboboxes in move&view about potential change
-            LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
-            if (instance)
-            {
-                instance->updateClickActionViews();
-            }
-        }
-
-        updateTable();
-        break;
-    case 2: // Cancel
-    default:
-        //exit;
-        break;
-    }
-}
-
-// Bypass to let Move & view read values without need to create own key binding handler
-// Assumes third person view
-// Might be better idea to just move whole mConflictHandler into LLFloaterPreference
-bool LLPanelPreferenceControls::canKeyBindHandle(const std::string &control, EMouseClickType click, KEY key, MASK mask)
-{
-    S32 mode = LLKeyConflictHandler::MODE_THIRD_PERSON;
-    if (mConflictHandler[mode].empty())
-    {
-        // opening for first time
-        mConflictHandler[mode].loadFromSettings(LLKeyConflictHandler::MODE_THIRD_PERSON);
-    }
-
-    return mConflictHandler[mode].canHandleControl(control, click, key, mask);
-}
-
-// Bypass to let Move & view modify values without need to create own key binding handler
-// Assumes third person view
-// Might be better idea to just move whole mConflictHandler into LLFloaterPreference
-void LLPanelPreferenceControls::setKeyBind(const std::string &control, EMouseClickType click, KEY key, MASK mask, bool set)
-{
-    S32 mode = LLKeyConflictHandler::MODE_THIRD_PERSON;
-    if (mConflictHandler[mode].empty())
-    {
-        // opening for first time
-        mConflictHandler[mode].loadFromSettings(LLKeyConflictHandler::MODE_THIRD_PERSON);
-    }
-
-    if (!mConflictHandler[mode].canAssignControl(mEditingControl))
-    {
-        return;
-    }
-
-    bool already_recorded = mConflictHandler[mode].canHandleControl(control, click, key, mask);
-    if (set)
-    {
-        if (already_recorded)
-        {
-            // nothing to do
-            return;
-        }
-
-        // find free spot to add data, if no free spot, assign to first
-        S32 index = 0;
-        for (S32 i = 0; i < 3; i++)
-        {
-            if (mConflictHandler[mode].getControl(control, i).isEmpty())
-            {
-                index = i;
-                break;
-            }
-        }
-        mConflictHandler[mode].registerControl(control, index, click, key, mask, true);
-    }
-    else if (!set)
-    {
-        if (!already_recorded)
-        {
-            // nothing to do
-            return;
-        }
-
-        // find specific control and reset it
-        for (S32 i = 0; i < 3; i++)
-        {
-            LLKeyData data = mConflictHandler[mode].getControl(control, i);
-            if (data.mMouse == click && data.mKey == key && data.mMask == mask)
-            {
-                mConflictHandler[mode].clearControl(control, i);
-            }
-        }
-    }
-}
-
-void LLPanelPreferenceControls::updateAndApply()
-{
-    S32 mode = LLKeyConflictHandler::MODE_THIRD_PERSON;
-    mConflictHandler[mode].saveToSettings(true);
-    updateTable();
-}
-
-// from LLSetKeybindDialog's interface
-bool LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes)
-{
-    if (!mConflictHandler[mEditingMode].canAssignControl(mEditingControl))
-    {
-        return true;
-    }
-
-    if ( mEditingColumn > 0)
-    {
-        if (all_modes)
-        {
-            for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
-            {
-                if (mConflictHandler[i].empty())
-                {
-                    mConflictHandler[i].loadFromSettings((LLKeyConflictHandler::ESourceMode)i);
-                }
-                mConflictHandler[i].registerControl(mEditingControl, mEditingColumn - 1, click, key, mask, true);
-                // Apply changes to viewer as 'temporary'
-                mConflictHandler[i].saveToSettings(true);
-            }
-        }
-        else
-        {
-            mConflictHandler[mEditingMode].registerControl(mEditingControl, mEditingColumn - 1, click, key, mask, true);
-            // Apply changes to viewer as 'temporary'
-            mConflictHandler[mEditingMode].saveToSettings(true);
-        }
-    }
-
-    updateTable();
-
-    if ((mEditingMode == LLKeyConflictHandler::MODE_THIRD_PERSON || all_modes)
-        && (mEditingControl == "walk_to"
-            || mEditingControl == "teleport_to"
-            || click == CLICK_LEFT
-            || click == CLICK_DOUBLELEFT))
-    {
-        // notify comboboxes in move&view about potential change
-        LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
-        if (instance)
-        {
-            instance->updateClickActionViews();
-        }
-    }
-
-    return true;
-}
-
-void LLPanelPreferenceControls::onDefaultKeyBind(bool all_modes)
-{
-    if (!mConflictHandler[mEditingMode].canAssignControl(mEditingControl))
-    {
-        return;
-    }
-    
-    if (mEditingColumn > 0)
-    {
-        if (all_modes)
-        {
-            for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
-            {
-                if (mConflictHandler[i].empty())
-                {
-                    mConflictHandler[i].loadFromSettings((LLKeyConflictHandler::ESourceMode)i);
-                }
-                mConflictHandler[i].resetToDefault(mEditingControl, mEditingColumn - 1);
-                // Apply changes to viewer as 'temporary'
-                mConflictHandler[i].saveToSettings(true);
-            }
-        }
-        else
-        {
-            mConflictHandler[mEditingMode].resetToDefault(mEditingControl, mEditingColumn - 1);
-            // Apply changes to viewer as 'temporary'
-            mConflictHandler[mEditingMode].saveToSettings(true);
-        }
-    }
-    updateTable();
-
-    if (mEditingMode == LLKeyConflictHandler::MODE_THIRD_PERSON || all_modes)
-    {
-        // notify comboboxes in move&view about potential change
-        LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
-        if (instance)
-        {
-            instance->updateClickActionViews();
-        }
-    }
-}
-
-void LLPanelPreferenceControls::onCancelKeyBind()
-{
-    pControlsTable->deselectAllItems();
-}
-
 LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const LLSD& key)
 	: LLFloater(key)
 {
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 1268935712..526214a617 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -37,17 +37,13 @@
 #include "llavatarpropertiesprocessor.h"
 #include "llconversationlog.h"
 #include "llsearcheditor.h"
-#include "llsetkeybinddialog.h"
-#include "llkeyconflict.h"
 
 class LLConversationLogObserver;
 class LLPanelPreference;
 class LLPanelLCD;
 class LLPanelDebug;
 class LLMessageSystem;
-class LLComboBox;
 class LLScrollListCtrl;
-class LLScrollListCell;
 class LLSliderCtrl;
 class LLSD;
 class LLTextBox;
@@ -106,8 +102,6 @@ public:
 	void selectPrivacyPanel();
 	void selectChatPanel();
 	void getControlNames(std::vector<std::string>& names);
-	// updates click/double-click action controls depending on values from settings.xml
-	void updateClickActionViews();
 
 protected:	
 	void		onBtnOK(const LLSD& userdata);
@@ -135,7 +129,9 @@ protected:
 
 	// callback for commit in the "Single click on land" and "Double click on land" comboboxes.
 	void onClickActionChange();
-	// updates click/double-click action keybindngs depending on view values
+	// updates click/double-click action settings depending on controls values
+	void updateClickActionSettings();
+	// updates click/double-click action controls depending on values from settings.xml
 	void updateClickActionControls();
 
 public:
@@ -150,6 +146,10 @@ public:
 	void onClickResetCache();
 	void onClickSkin(LLUICtrl* ctrl,const LLSD& userdata);
 	void onSelectSkin();
+	void onClickSetKey();
+	void setKey(KEY key);
+	void setMouse(LLMouseHandler::EClickType click);
+	void onClickSetMiddleMouse();
 	void onClickSetSounds();
 	void onClickEnablePopup();
 	void onClickDisablePopup();	
@@ -204,6 +204,7 @@ private:
 
 	static std::string sSkin;
 	notifications_map mNotificationOptions;
+	bool mClickActionDirty; ///< Set to true when the click/double-click options get changed by user.
 	bool mGotPersonalInfo;
 	bool mOriginalIMViaEmail;
 	bool mLanguageChanged;
@@ -293,60 +294,6 @@ private:
 	LOG_CLASS(LLPanelPreferenceGraphics);
 };
 
-class LLPanelPreferenceControls : public LLPanelPreference, public LLKeyBindResponderInterface
-{
-	LOG_CLASS(LLPanelPreferenceControls);
-public:
-	LLPanelPreferenceControls();
-	virtual ~LLPanelPreferenceControls();
-
-	BOOL postBuild();
-
-	void apply();
-	void cancel();
-	void saveSettings();
-	void resetDirtyChilds();
-
-	void onListCommit();
-	void onModeCommit();
-	void onRestoreDefaultsBtn();
-	void onRestoreDefaultsResponse(const LLSD& notification, const LLSD& response);
-
-    // Bypass to let Move & view read values without need to create own key binding handler
-    // Todo: consider a better way to share access to keybindings
-    bool canKeyBindHandle(const std::string &control, EMouseClickType click, KEY key, MASK mask);
-    // Bypasses to let Move & view modify values without need to create own key binding handler
-    void setKeyBind(const std::string &control, EMouseClickType click, KEY key, MASK mask, bool set /*set or reset*/ );
-    void updateAndApply();
-
-    // from interface
-	/*virtual*/ bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes);
-    /*virtual*/ void onDefaultKeyBind(bool all_modes);
-    /*virtual*/ void onCancelKeyBind();
-
-private:
-	// reloads settings, discards current changes, updates table
-	void regenerateControls();
-
-	// These fuctions do not clean previous content
-	bool addControlTableColumns(const std::string &filename);
-	bool addControlTableRows(const std::string &filename);
-	void addControlTableSeparator();
-
-	// Cleans content and then adds content from xml files according to current mEditingMode
-    void populateControlTable();
-
-    // Updates keybindings from storage to table
-    void updateTable();
-
-	LLScrollListCtrl* pControlsTable;
-	LLComboBox *pKeyModeBox;
-	LLKeyConflictHandler mConflictHandler[LLKeyConflictHandler::MODE_COUNT];
-	std::string mEditingControl;
-	S32 mEditingColumn;
-	S32 mEditingMode;
-};
-
 class LLFloaterPreferenceGraphicsAdvanced : public LLFloater
 {
   public: 
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
deleted file mode 100644
index 8ee50d5c52..0000000000
--- a/indra/newview/llkeyconflict.cpp
+++ /dev/null
@@ -1,989 +0,0 @@
-/** 
- * @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 "lltrans.h"
-#include "llviewercontrol.h"
-#include "llviewerinput.h"
-#include "llviewermenu.h"
-#include "llxuiparser.h"
-
-static const std::string saved_settings_key_controls[] = { "placeholder" }; // add settings from gSavedSettings here
-
-static const std::string filename_default = "key_bindings.xml";
-static const std::string filename_temporary = "key_bindings_tmp.xml"; // used to apply uncommited changes on the go.
-
-// 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;
-}
-
-std::string string_from_mouse(EMouseClickType click, bool translate)
-{
-    std::string res;
-    switch (click)
-    {
-    case CLICK_LEFT:
-        res = "LMB";
-        break;
-    case CLICK_MIDDLE:
-        res = "MMB";
-        break;
-    case CLICK_RIGHT:
-        res = "RMB";
-        break;
-    case CLICK_BUTTON4:
-        res = "MB4";
-        break;
-    case CLICK_BUTTON5:
-        res = "MB5";
-        break;
-    case CLICK_DOUBLELEFT:
-        res = "Double LMB";
-        break;
-    default:
-        break;
-    }
-
-    if (translate && !res.empty())
-    {
-        res = LLTrans::getString(res);
-    }
-    return res;
-}
-
-// LLKeyConflictHandler
-
-S32 LLKeyConflictHandler::sTemporaryFileUseCount = 0;
-
-LLKeyConflictHandler::LLKeyConflictHandler()
-:   mHasUnsavedChanges(false),
-    mUsesTemporaryFile(false),
-    mLoadMode(MODE_COUNT)
-{
-}
-
-LLKeyConflictHandler::LLKeyConflictHandler(ESourceMode mode)
-:   mHasUnsavedChanges(false),
-    mUsesTemporaryFile(false),
-    mLoadMode(mode)
-{
-    loadFromSettings(mode);
-}
-
-LLKeyConflictHandler::~LLKeyConflictHandler()
-{
-    clearUnsavedChanges();
-    // Note: does not reset bindings if temporary file was used
-}
-
-bool LLKeyConflictHandler::canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask)
-{
-    return mControlsMap[control_name].canHandle(mouse_ind, key, mask);
-}
-
-bool LLKeyConflictHandler::canHandleKey(const std::string &control_name, KEY key, MASK mask)
-{
-    return canHandleControl(control_name, CLICK_NONE, key, mask);
-}
-
-bool LLKeyConflictHandler::canHandleMouse(const std::string &control_name, EMouseClickType mouse_ind, MASK mask)
-{
-    return canHandleControl(control_name, mouse_ind, KEY_NONE, mask);
-}
-
-bool LLKeyConflictHandler::canHandleMouse(const std::string &control_name, S32 mouse_ind, MASK mask)
-{
-    return canHandleControl(control_name, (EMouseClickType)mouse_ind, KEY_NONE, mask);
-}
-
-bool LLKeyConflictHandler::canAssignControl(const std::string &control_name)
-{
-    control_map_t::iterator iter = mControlsMap.find(control_name);
-    if (iter != mControlsMap.end())
-    {
-        return iter->second.mAssignable;
-    }
-    // If we don't know this control, means it wasn't assigned by user yet and thus is editable
-    return true;
-}
-
-// static
-bool LLKeyConflictHandler::isReservedByMenu(const KEY &key, const MASK &mask)
-{
-    if (key == KEY_NONE)
-    {
-        return false;
-    }
-    return (gMenuBarView && gMenuBarView->hasAccelerator(key, mask))
-           || (gLoginMenuBarView && gLoginMenuBarView->hasAccelerator(key, mask));
-}
-
-// static
-bool LLKeyConflictHandler::isReservedByMenu(const LLKeyData &data)
-{
-    if (data.mMouse != CLICK_NONE || data.mKey == KEY_NONE)
-    {
-        return false;
-    }
-    return (gMenuBarView && gMenuBarView->hasAccelerator(data.mKey, data.mMask))
-           || (gLoginMenuBarView && gLoginMenuBarView->hasAccelerator(data.mKey, data.mMask));
-}
-
-bool LLKeyConflictHandler::registerControl(const std::string &control_name, U32 index, EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask)
-{
-    if (control_name.empty())
-    {
-        return false;
-    }
-    LLKeyConflict &type_data = mControlsMap[control_name];
-    if (!type_data.mAssignable)
-    {
-        // Example: user tried to assign camera spin to all modes, but first person mode doesn't support it
-        return false;
-    }
-    LLKeyData data(mouse, key, mask, ignore_mask);
-    if (type_data.mKeyBind.getKeyData(index) == data)
-    {
-        return true;
-    }
-    if (isReservedByMenu(data))
-    {
-        return false;
-    }
-    if (removeConflicts(data, type_data.mConflictMask))
-    {
-        type_data.mKeyBind.replaceKeyData(data, index);
-        mHasUnsavedChanges = true;
-        return true;
-    }
-    // control already in use/blocked
-    return false;
-}
-
-bool LLKeyConflictHandler::clearControl(const std::string &control_name, U32 data_index)
-{
-    if (control_name.empty())
-    {
-        return false;
-    }
-    LLKeyConflict &type_data = mControlsMap[control_name];
-    if (!type_data.mAssignable)
-    {
-        // Example: user tried to assign camera spin to all modes, but first person mode doesn't support it
-        return false;
-    }
-    type_data.mKeyBind.resetKeyData(data_index);
-    mHasUnsavedChanges = true;
-    return true;
-}
-
-LLKeyData LLKeyConflictHandler::getControl(const std::string &control_name, U32 index)
-{
-    if (control_name.empty())
-    {
-        return LLKeyData();
-    }
-    return mControlsMap[control_name].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)
-    {
-        result = LLKeyboard::stringFromAccelerator(keydata.mMask);
-    }
-
-    result += string_from_mouse(keydata.mMouse, true);
-
-    return result;
-}
-
-std::string LLKeyConflictHandler::getControlString(const std::string &control_name, U32 index)
-{
-    if (control_name.empty())
-    {
-        return "";
-    }
-    return getStringFromKeyData(mControlsMap[control_name].getKeyData(index));
-}
-
-void LLKeyConflictHandler::loadFromControlSettings(const std::string &name)
-{
-    LLControlVariablePtr var = gSavedSettings.getControl(name);
-    if (var)
-    {
-        LLKeyBind bind(var->getValue());
-        LLKeyConflict key(bind, true, 0);
-        mControlsMap[name] = key;
-    }
-}
-
-void LLKeyConflictHandler::loadFromSettings(const LLViewerInput::KeyMode& keymode, control_map_t *destination)
-{
-    for (LLInitParam::ParamIterator<LLViewerInput::KeyBinding>::const_iterator it = keymode.bindings.begin(),
-        end_it = keymode.bindings.end();
-        it != end_it;
-    ++it)
-    {
-        KEY key;
-        MASK mask;
-        EMouseClickType mouse = CLICK_NONE;
-        if (it->mouse.isProvided())
-        {
-            LLViewerInput::mouseFromString(it->mouse.getValue(), &mouse);
-        }
-        if (it->key.getValue().empty())
-        {
-            key = KEY_NONE;
-        }
-        else
-        {
-            LLKeyboard::keyFromString(it->key, &key);
-        }
-        LLKeyboard::maskFromString(it->mask, &mask);
-        // Note: it->command is also the name of UI element, howhever xml we are loading from
-        // might not know all the commands, so UI will have to know what to fill by its own
-        // Assumes U32_MAX conflict mask, and is assignable by default,
-        // but assignability might have been overriden by generatePlaceholders.
-        LLKeyConflict &type_data = (*destination)[it->command];
-        type_data.mKeyBind.addKeyData(mouse, key, mask, true);
-    }
-}
-
-bool LLKeyConflictHandler::loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination)
-{
-    if (filename.empty())
-    {
-        return false;
-    }
-
-    bool res = false;
-
-    LLViewerInput::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);
-                res = true;
-            }
-            break;
-        case MODE_THIRD_PERSON:
-            if (keys.third_person.isProvided())
-            {
-                loadFromSettings(keys.third_person, destination);
-                res = true;
-            }
-            break;
-        case MODE_EDIT_AVATAR:
-            if (keys.edit_avatar.isProvided())
-            {
-                loadFromSettings(keys.edit_avatar, destination);
-                res = true;
-            }
-            break;
-        case MODE_SITTING:
-            if (keys.sitting.isProvided())
-            {
-                loadFromSettings(keys.sitting, destination);
-                res = true;
-            }
-            break;
-        default:
-            LL_ERRS() << "Not implememted mode " << load_mode << LL_ENDL;
-            break;
-        }
-    }
-    return res;
-}
-
-void LLKeyConflictHandler::loadFromSettings(ESourceMode load_mode)
-{
-    mControlsMap.clear();
-    mDefaultsMap.clear();
-
-    // E.X. In case we need placeholder keys for conflict resolution.
-    generatePlaceholders(load_mode);
-
-    if (load_mode == MODE_SAVED_SETTINGS)
-    {
-        // load settings clss knows about, but it also possible to load settings by name separately
-        const S32 size = std::extent<decltype(saved_settings_key_controls)>::value;
-        for (U32 i = 0; i < size; i++)
-        {
-            loadFromControlSettings(saved_settings_key_controls[i]);
-        }
-    }
-    else
-    {
-        // load defaults
-        std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, filename_default);
-        if (!loadFromSettings(load_mode, filename, &mDefaultsMap))
-        {
-            LL_WARNS() << "Failed to load default settings, aborting" << LL_ENDL;
-            return;
-        }
-
-        // load user's
-        filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default);
-        if (!gDirUtilp->fileExists(filename) || !loadFromSettings(load_mode, filename, &mControlsMap))
-        {
-            // mind placeholders
-            mControlsMap.insert(mDefaultsMap.begin(), mDefaultsMap.end());
-        }
-    }
-    mLoadMode = load_mode;
-}
-
-void LLKeyConflictHandler::saveToSettings(bool temporary)
-{
-    if (mControlsMap.empty())
-    {
-        return;
-    }
-
-    if (mLoadMode == MODE_SAVED_SETTINGS)
-    {
-        // Does not support 'temporary', preferences handle that themself
-        // so in case of saved settings we just do not clear mHasUnsavedChanges
-        control_map_t::iterator iter = mControlsMap.begin();
-        control_map_t::iterator end = mControlsMap.end();
-
-        for (; iter != end; ++iter)
-        {
-            if (iter->first.empty())
-            {
-                continue;
-            }
-
-            LLKeyConflict &key = iter->second;
-            key.mKeyBind.trimEmpty();
-            if (!key.mAssignable)
-            {
-                continue;
-            }
-
-            if (gSavedSettings.controlExists(iter->first))
-            {
-                gSavedSettings.setLLSD(iter->first, key.mKeyBind.asLLSD());
-            }
-            else if (!key.mKeyBind.empty())
-            {
-                // Note: this is currently not in use, might be better for load mechanics to ask for and retain control group
-                // otherwise settings loaded from other control groups will end in gSavedSettings
-                LL_INFOS() << "Creating new keybinding " << iter->first << LL_ENDL;
-                gSavedSettings.declareLLSD(iter->first, key.mKeyBind.asLLSD(), "comment", LLControlVariable::PERSIST_ALWAYS);
-            }
-        }
-    }
-    else
-    {
-        // Determine what file to load and load full copy of that file
-        std::string filename;
-
-        if (temporary)
-        {
-            filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_temporary);
-            if (!gDirUtilp->fileExists(filename))
-            {
-                filename.clear();
-            }
-        }
-
-        if (filename.empty())
-        {
-            filename = gDirUtilp->findFile(filename_default,
-                gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
-                gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
-        }
-
-        LLViewerInput::Keys keys;
-        LLSimpleXUIParser parser;
-
-        if (parser.readXUI(filename, keys)
-            && keys.validateBlock())
-        {
-            // replace category we edited
-
-            // mode is a HACK to correctly reset bindings without reparsing whole file and avoid doing
-            // own param container (which will face issues with inasseesible members of LLInitParam)
-            LLViewerInput::KeyMode mode;
-            LLViewerInput::KeyBinding binding;
-
-            control_map_t::iterator iter = mControlsMap.begin();
-            control_map_t::iterator end = mControlsMap.end();
-            for (; iter != end; ++iter)
-            {
-                // By default xml have (had) up to 6 elements per function
-                // eventually it will be cleaned up and UI will only shows 3 per function,
-                // so make sure to cleanup.
-                // Also this helps in keeping file small.
-                iter->second.mKeyBind.trimEmpty();
-                U32 size = iter->second.mKeyBind.getDataCount();
-                for (U32 i = 0; i < size; ++i)
-                {
-                    if (iter->first.empty())
-                    {
-                        continue;
-                    }
-
-                    LLKeyConflict &key = iter->second;
-                    key.mKeyBind.trimEmpty();
-                    if (key.mKeyBind.empty() || !key.mAssignable)
-                    {
-                        continue;
-                    }
-
-                    LLKeyData data = key.mKeyBind.getKeyData(i);
-                    // Still write empty LLKeyData to make sure we will maintain UI position
-                    if (data.mKey == KEY_NONE)
-                    {
-                        // Might be better idea to be consistent and use NONE. LLViewerInput can work with both cases
-                        binding.key = "";
-                    }
-                    else
-                    {
-                        binding.key = LLKeyboard::stringFromKey(data.mKey, false /*Do not localize*/);
-                    }
-                    binding.mask = string_from_mask(data.mMask);
-                    if (data.mMouse == CLICK_NONE)
-                    {
-                        binding.mouse.setProvided(false);
-                    }
-                    else
-                    {
-                        // set() because 'optional', for compatibility purposes
-                        // just copy old keys.xml and rename to key_bindings.xml, it should work
-                        binding.mouse.set(string_from_mouse(data.mMouse, false), true);
-                    }
-                    binding.command = iter->first;
-                    mode.bindings.add(binding);
-                }
-            }
-
-            switch (mLoadMode)
-            {
-            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_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:
-                LL_ERRS() << "Not implememted mode " << mLoadMode << LL_ENDL;
-                break;
-            }
-
-            if (temporary)
-            {
-                // write to temporary xml and use it for gViewerInput
-                filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_temporary);
-                if (!mUsesTemporaryFile)
-                {
-                    mUsesTemporaryFile = true;
-                    sTemporaryFileUseCount++;
-                }
-            }
-            else
-            {
-                // write back to user's xml and use it for gViewerInput
-                filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default);
-                // Don't reset mUsesTemporaryFile, it will be reset at cleanup stage
-            }
-
-            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))
-            {
-                // Ideally instead of rebinding immediately we should shedule
-                // the rebind since single file can have multiple handlers,
-                // one per mode, saving simultaneously.
-                // Or whatever uses LLKeyConflictHandler should control the process.
-                gViewerInput.loadBindingsXML(filename);
-            }
-        }
-    }
-
-#if 1
-    // Legacy support
-    // Remove #if-#endif section half a year after DRTVWR-501 releases.
-    // Update legacy settings in settings.xml
-    // We only care for third person view since legacy settings can't store
-    // more than one mode.
-    // We are saving this even if we are in temporary mode - preferences
-    // will restore values on cancel
-    if (mLoadMode == MODE_THIRD_PERSON && mHasUnsavedChanges)
-    {
-        bool value = canHandleMouse("walk_to", CLICK_DOUBLELEFT, MASK_NONE);
-        gSavedSettings.setBOOL("DoubleClickAutoPilot", value);
-
-        value = canHandleMouse("walk_to", CLICK_LEFT, MASK_NONE);
-        gSavedSettings.setBOOL("ClickToWalk", value);
-
-        // new method can save both toggle and push-to-talk values simultaneously,
-        // but legacy one can save only one. It also doesn't support mask.
-        LLKeyData data = getControl("toggle_voice", 0);
-        bool can_toggle = !data.isEmpty();
-        if (!can_toggle)
-        {
-            data = getControl("voice_follow_key", 0);
-        }
-
-        gSavedSettings.setBOOL("PushToTalkToggle", can_toggle);
-        if (data.isEmpty())
-        {
-            // legacy viewer has a bug that might crash it if NONE value is assigned.
-            // just reset to default
-            gSavedSettings.getControl("PushToTalkButton")->resetToDefault(false);
-        }
-        else
-        {
-            if (data.mKey != KEY_NONE)
-            {
-                gSavedSettings.setString("PushToTalkButton", LLKeyboard::stringFromKey(data.mKey));
-            }
-            else
-            {
-                std::string ctrl_value;
-                switch (data.mMouse)
-                {
-                case CLICK_MIDDLE:
-                    ctrl_value = "MiddleMouse";
-                    break;
-                case CLICK_BUTTON4:
-                    ctrl_value = "MouseButton4";
-                    break;
-                case CLICK_BUTTON5:
-                    ctrl_value = "MouseButton5";
-                    break;
-                default:
-                    ctrl_value = "MiddleMouse";
-                    break;
-                }
-                gSavedSettings.setString("PushToTalkButton", ctrl_value);
-            }
-        }
-    }
-#endif
-
-    if (mLoadMode == MODE_THIRD_PERSON && mHasUnsavedChanges)
-    {
-        // Map floater should react to doubleclick if doubleclick for teleport is set
-        // Todo: Seems conterintuitive for map floater to share inworld controls
-        // after these changes release, discuss with UI UX engineer if this should just
-        // be set to 1 by default (before release this also doubles as legacy support)
-        bool value = canHandleMouse("teleport_to", CLICK_DOUBLELEFT, MASK_NONE);
-        gSavedSettings.setBOOL("DoubleClickTeleport", value);
-    }
-
-    if (!temporary)
-    {
-        // will remove any temporary file if there were any
-        clearUnsavedChanges();
-    }
-}
-
-LLKeyData LLKeyConflictHandler::getDefaultControl(const std::string &control_name, U32 index)
-{
-    if (control_name.empty())
-    {
-        return LLKeyData();
-    }
-    if (mLoadMode == MODE_SAVED_SETTINGS)
-    {
-        LLControlVariablePtr var = gSavedSettings.getControl(control_name);
-        if (var)
-        {
-            return LLKeyBind(var->getDefault()).getKeyData(index);
-        }
-        return LLKeyData();
-    }
-    else
-    {
-        control_map_t::iterator iter = mDefaultsMap.find(control_name);
-        if (iter != mDefaultsMap.end())
-        {
-            return iter->second.mKeyBind.getKeyData(index);
-        }
-        return LLKeyData();
-    }
-}
-
-void LLKeyConflictHandler::resetToDefault(const std::string &control_name, U32 index)
-{
-    if (control_name.empty())
-    {
-        return;
-    }
-    LLKeyData data = getDefaultControl(control_name, index);
-
-    if (data != mControlsMap[control_name].getKeyData(index))
-    {
-        // reset controls that might have been switched to our current control
-        removeConflicts(data, mControlsMap[control_name].mConflictMask);
-        mControlsMap[control_name].setKeyData(data, index);
-    }
-}
-
-void LLKeyConflictHandler::resetToDefaultAndResolve(const std::string &control_name, bool ignore_conflicts)
-{
-    if (control_name.empty())
-    {
-        return;
-    }
-    if (mLoadMode == MODE_SAVED_SETTINGS)
-    {
-        LLControlVariablePtr var = gSavedSettings.getControl(control_name);
-        if (var)
-        {
-            LLKeyBind bind(var->getDefault());
-            if (!ignore_conflicts)
-            {
-                for (S32 i = 0; i < bind.getDataCount(); ++i)
-                {
-                    removeConflicts(bind.getKeyData(i), mControlsMap[control_name].mConflictMask);
-                }
-            }
-            mControlsMap[control_name].mKeyBind = bind;
-        }
-        else
-        {
-            mControlsMap[control_name].mKeyBind.clear();
-        }
-    }
-    else
-    {
-        control_map_t::iterator iter = mDefaultsMap.find(control_name);
-        if (iter != mDefaultsMap.end())
-        {
-            if (!ignore_conflicts)
-            {
-                for (S32 i = 0; i < iter->second.mKeyBind.getDataCount(); ++i)
-                {
-                    removeConflicts(iter->second.mKeyBind.getKeyData(i), mControlsMap[control_name].mConflictMask);
-                }
-            }
-            mControlsMap[control_name].mKeyBind = iter->second.mKeyBind;
-        }
-        else
-        {
-            mControlsMap[control_name].mKeyBind.clear();
-        }
-    }
-}
-
-void LLKeyConflictHandler::resetToDefault(const std::string &control_name)
-{
-    // reset specific binding without ignoring conflicts
-    resetToDefaultAndResolve(control_name, false);
-}
-
-void LLKeyConflictHandler::resetToDefaults(ESourceMode mode)
-{
-    if (mode == MODE_SAVED_SETTINGS)
-    {
-        control_map_t::iterator iter = mControlsMap.begin();
-        control_map_t::iterator end = mControlsMap.end();
-
-        for (; iter != end; ++iter)
-        {
-            resetToDefaultAndResolve(iter->first, true);
-        }
-    }
-    else
-    {
-        mControlsMap.clear();
-        generatePlaceholders(mode);
-        mControlsMap.insert(mDefaultsMap.begin(), mDefaultsMap.end());
-    }
-
-    mHasUnsavedChanges = true;
-}
-
-void LLKeyConflictHandler::resetToDefaults()
-{
-    if (!empty())
-    {
-        resetToDefaults(mLoadMode);
-    }
-    else
-    {
-        // not optimal since:
-        // 1. We are not sure that mLoadMode was set
-        // 2. We are not sure if there are any changes in comparison to default
-        // 3. We are loading 'current' only to replace it
-        // but it is reliable and works Todo: consider optimizing.
-        loadFromSettings(mLoadMode);
-        resetToDefaults(mLoadMode);
-    }
-}
-
-void LLKeyConflictHandler::clear()
-{
-    if (clearUnsavedChanges())
-    {
-        // temporary file was removed, this means we were using it and need to reload keyboard's bindings
-        resetKeyboardBindings();
-    }
-    mControlsMap.clear();
-    mDefaultsMap.clear();
-}
-
-// static
-void LLKeyConflictHandler::resetKeyboardBindings()
-{
-    // Try to load User's bindings first
-    std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_default);
-    if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file))
-    {
-        // Failed to load custom bindings, try default ones
-        key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, filename_default);
-        if (!gViewerInput.loadBindingsXML(key_bindings_file))
-        {
-            LL_ERRS("InitInfo") << "Unable to open default key bindings from " << key_bindings_file << LL_ENDL;
-        }
-    }
-}
-
-void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode)
-{
-    // These controls are meant to cause conflicts when user tries to assign same control somewhere else
-    // also this can be used to pre-record controls that should not conflict or to assign conflict groups/masks
-
-    if (load_mode == MODE_FIRST_PERSON)
-    {
-        // First person view doesn't support camera controls
-        // Note: might be better idea to just load these from control_table_contents_camera.xml
-        // or to pass from floaterpreferences when it loads said file
-        registerTemporaryControl("look_up");
-        registerTemporaryControl("look_down");
-        registerTemporaryControl("move_forward");
-        registerTemporaryControl("move_backward");
-        registerTemporaryControl("move_forward_fast");
-        registerTemporaryControl("move_backward_fast");
-        registerTemporaryControl("spin_over");
-        registerTemporaryControl("spin_under");
-        registerTemporaryControl("pan_up");
-        registerTemporaryControl("pan_down");
-        registerTemporaryControl("pan_left");
-        registerTemporaryControl("pan_right");
-        registerTemporaryControl("pan_in");
-        registerTemporaryControl("pan_out");
-        registerTemporaryControl("spin_around_ccw");
-        registerTemporaryControl("spin_around_cw");
-
-        // control_table_contents_editing.xml
-        registerTemporaryControl("edit_avatar_spin_ccw");
-        registerTemporaryControl("edit_avatar_spin_cw");
-        registerTemporaryControl("edit_avatar_spin_over");
-        registerTemporaryControl("edit_avatar_spin_under");
-        registerTemporaryControl("edit_avatar_move_forward");
-        registerTemporaryControl("edit_avatar_move_backward");
-    }
-
-    if (load_mode != MODE_SITTING)
-    {
-        registerTemporaryControl("move_forward_sitting");
-        registerTemporaryControl("move_backward_sitting");
-        registerTemporaryControl("spin_over_sitting");
-        registerTemporaryControl("spin_under_sitting");
-        registerTemporaryControl("spin_around_ccw_sitting");
-        registerTemporaryControl("spin_around_cw_sitting");
-    }
-}
-
-bool LLKeyConflictHandler::removeConflicts(const LLKeyData &data, const U32 &conlict_mask)
-{
-    if (conlict_mask == CONFLICT_NOTHING)
-    {
-        // Can't conflict
-        return true;
-    }
-    std::map<std::string, S32> conflict_list;
-    control_map_t::iterator cntrl_iter = mControlsMap.begin();
-    control_map_t::iterator cntrl_end = mControlsMap.end();
-    for (; cntrl_iter != cntrl_end; ++cntrl_iter)
-    {
-        S32 index = cntrl_iter->second.mKeyBind.findKeyData(data);
-        if (index >= 0
-            && cntrl_iter->second.mConflictMask != CONFLICT_NOTHING
-            && (cntrl_iter->second.mConflictMask & conlict_mask) != 0)
-        {
-            if (cntrl_iter->second.mAssignable)
-            {
-                // Potentially we can have multiple conflict flags conflicting
-                // including unassignable keys.
-                // So record the conflict and find all others before doing any changes.
-                // Assume that there is only one conflict per bind
-                conflict_list[cntrl_iter->first] = index;
-            }
-            else
-            {
-                return false;
-            }
-        }
-    }
-
-    std::map<std::string, S32>::iterator cnflct_iter = conflict_list.begin();
-    std::map<std::string, S32>::iterator cnflct_end = conflict_list.end();
-    for (; cnflct_iter != cnflct_end; ++cnflct_iter)
-    {
-        mControlsMap[cnflct_iter->first].mKeyBind.resetKeyData(cnflct_iter->second);
-    }
-    return true;
-}
-
-void LLKeyConflictHandler::registerTemporaryControl(const std::string &control_name, EMouseClickType mouse, KEY key, MASK mask, U32 conflict_mask)
-{
-    LLKeyConflict *type_data = &mControlsMap[control_name];
-    type_data->mAssignable = false;
-    type_data->mConflictMask = conflict_mask;
-    type_data->mKeyBind.addKeyData(mouse, key, mask, false);
-}
-
-void LLKeyConflictHandler::registerTemporaryControl(const std::string &control_name, U32 conflict_mask)
-{
-    LLKeyConflict *type_data = &mControlsMap[control_name];
-    type_data->mAssignable = false;
-    type_data->mConflictMask = conflict_mask;
-}
-
-bool LLKeyConflictHandler::clearUnsavedChanges()
-{
-    bool result = false;
-    mHasUnsavedChanges = false;
-
-    if (mUsesTemporaryFile)
-    {
-        mUsesTemporaryFile = false;
-        sTemporaryFileUseCount--;
-        if (!sTemporaryFileUseCount)
-        {
-            result = clearTemporaryFile();
-        }
-        // else: might be usefull to overwrite content of temp file with defaults
-        // but at the moment there is no such need
-    }
-    return result;
-}
-
-//static
-bool LLKeyConflictHandler::clearTemporaryFile()
-{
-    // At the moment single file needs five handlers (one per mode), so doing this
-    // will remove file for all hadlers
-    std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename_temporary);
-    if (gDirUtilp->fileExists(filename))
-    {
-        LLFile::remove(filename);
-        return true;
-    }
-    return false;
-}
-
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
deleted file mode 100644
index 7566303cdd..0000000000
--- a/indra/newview/llkeyconflict.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/** 
- * @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 "llviewerinput.h"
-
-
-class LLKeyConflict
-{
-public:
-    LLKeyConflict() : mAssignable(true), mConflictMask(U32_MAX) {} //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 ESourceMode // partially repeats e_keyboard_mode
-    {
-        MODE_FIRST_PERSON,
-        MODE_THIRD_PERSON,
-        MODE_EDIT_AVATAR,
-        MODE_SITTING,
-        MODE_SAVED_SETTINGS, // for settings from saved settings
-        MODE_COUNT
-    };
-
-    const U32 CONFLICT_NOTHING = 0;
-    // at the moment this just means that key will conflict with everything that is identical
-    const U32 CONFLICT_ANY = U32_MAX;
-
-    // Note: missed selection and edition commands (would be really nice to go through selection via MB4/5 or wheel)
-
-    LLKeyConflictHandler();
-    LLKeyConflictHandler(ESourceMode mode);
-    ~LLKeyConflictHandler();
-
-    bool canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask);
-    bool canHandleKey(const std::string &control_name, KEY key, MASK mask);
-    bool canHandleMouse(const std::string &control_name, EMouseClickType mouse_ind, MASK mask);
-    bool canHandleMouse(const std::string &control_name, S32 mouse_ind, MASK mask); //Just for convinience
-    bool canAssignControl(const std::string &control_name);
-    static bool isReservedByMenu(const KEY &key, const MASK &mask);
-    static bool isReservedByMenu(const LLKeyData &data);
-
-    // @control_name - see REGISTER_KEYBOARD_ACTION in llviewerinput for avaliable options,
-    // usually this is just name of the function
-    // @data_index - single control (function) can have multiple key combinations trigering
-    // it, this index indicates combination function will change/add; Note that preferences
-    // floater can only display up to 3 options, but data_index can be bigger than that
-    // @mouse_ind - mouse action (middle click, MB5 etc)
-    // @key - keyboard key action
-    // @mask - shift/ctrl/alt flags
-    // @ignore_mask - Either to expect exact match (ctrl+K will not trigger if ctrl+shift+K
-    // is active) or ignore not expected masks as long as expected mask is present
-    // (ctrl+K will be triggered if ctrl+shift+K is active)
-    bool registerControl(const std::string &control_name, U32 data_index, EMouseClickType mouse_ind, KEY key, MASK mask, bool ignore_mask); //todo: return conflicts?
-    bool clearControl(const std::string &control_name, U32 data_index);
-
-    LLKeyData getControl(const std::string &control_name, U32 data_index);
-
-    // localized string
-    static std::string getStringFromKeyData(const LLKeyData& keydata);
-    std::string getControlString(const std::string &control_name, U32 data_index);
-
-    // Load single control, overrides existing one if names match
-    void loadFromControlSettings(const std::string &name);
-    // Drops any changes loads controls with ones from 'saved settings' or from xml
-    void loadFromSettings(ESourceMode load_mode);
-
-    // Saves settings to 'saved settings' or to xml
-    // If 'temporary' is set, function will save settings to temporary
-    // file and reload input bindings from temporary file.
-    // 'temporary' does not support gSavedSettings, those are handled
-    // by preferences, so 'temporary' is such case will simply not
-    // reset mHasUnsavedChanges
-    //
-    // 'temporary' exists to support ability of live-editing settings in
-    // preferences: temporary for testing changes 'live' without saving them,
-    // then hitting ok/cancel and save/discard values permanently.
-    void saveToSettings(bool apply_temporary = false);
-
-    LLKeyData getDefaultControl(const std::string &control_name, U32 data_index);
-    // Resets keybinding to default variant from 'saved settings' or xml
-    void resetToDefault(const std::string &control_name, U32 index);
-    void resetToDefault(const std::string &control_name);
-    // resets current mode to defaults
-    void resetToDefaults();
-
-    bool empty() { return mControlsMap.empty(); }
-    void clear();
-
-    // reloads bindings from last valid user's xml or from default xml
-    // to keyboard's handler
-    static void resetKeyboardBindings();
-
-    bool hasUnsavedChanges() { return mHasUnsavedChanges; }
-    void setLoadMode(ESourceMode mode) { mLoadMode = mode; }
-    ESourceMode getLoadMode() { return mLoadMode; }
-
-private:
-    void resetToDefaultAndResolve(const std::string &control_name, bool ignore_conflicts);
-    void resetToDefaults(ESourceMode mode);
-
-    // at the moment these kind of control is not savable, but takes part in conflict resolution
-    void registerTemporaryControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask, U32 conflict_mask);
-    void registerTemporaryControl(const std::string &control_name, U32 conflict_mask = 0);
-
-    typedef std::map<std::string, LLKeyConflict> control_map_t;
-    void loadFromSettings(const LLViewerInput::KeyMode& keymode, control_map_t *destination);
-    bool loadFromSettings(const ESourceMode &load_mode, const std::string &filename, control_map_t *destination);
-    void generatePlaceholders(ESourceMode load_mode); //E.x. non-assignable values
-    // returns false in case user is trying to reuse control that can't be reassigned
-    bool removeConflicts(const LLKeyData &data, const U32 &conlict_mask);
-
-    // removes flags and removes temporary file, returns 'true' if file was removed
-    bool clearUnsavedChanges();
-    // return true if there was a file to remove
-    static bool clearTemporaryFile();
-
-    control_map_t mControlsMap;
-    control_map_t mDefaultsMap;
-    bool mHasUnsavedChanges;
-    ESourceMode mLoadMode;
-
-    // To implement 'apply immediately'+revert on cancel, class applies changes to temporary file
-    // but this only works for settings from keybndings files (key_bindings.xml)
-    // saved setting rely onto external mechanism of preferences floater
-    bool mUsesTemporaryFile;
-    static S32 sTemporaryFileUseCount;
-};
-
-
-#endif  // LL_LLKEYCONFLICT_H
diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp
deleted file mode 100644
index 4eb76c9d89..0000000000
--- a/indra/newview/llsetkeybinddialog.cpp
+++ /dev/null
@@ -1,346 +0,0 @@
-/** 
- * @file llsetkeybinddialog.cpp
- * @brief LLSetKeyBindDialog class implementation.
- *
- * $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$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llsetkeybinddialog.h"
-
-#include "llbutton.h"
-#include "llcheckboxctrl.h"
-#include "lleventtimer.h"
-#include "llfloaterreg.h"
-#include "llfocusmgr.h"
-#include "llkeyconflict.h"
-#include "llviewercontrol.h"
-
-class LLSetKeyBindDialog::Updater : public LLEventTimer
-{
-public:
-
-    typedef boost::function<void(MASK)> callback_t;
-
-    Updater(callback_t cb, F32 period, MASK mask)
-        :LLEventTimer(period),
-        mMask(mask),
-        mCallback(cb)
-    {
-        mEventTimer.start();
-    }
-
-    virtual ~Updater(){}
-
-protected:
-    BOOL tick()
-    {
-        mCallback(mMask);
-        // Deletes itseft after execution
-        return TRUE;
-    }
-
-private:
-    MASK mMask;
-    callback_t mCallback;
-};
-
-bool LLSetKeyBindDialog::sRecordKeys = false;
-
-LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key)
-    : LLModalDialog(key),
-    pParent(NULL),
-    mKeyFilterMask(DEFAULT_KEY_FILTER),
-    pUpdater(NULL),
-    mContextConeOpacity(0.f),
-    mContextConeInAlpha(0.f),
-    mContextConeOutAlpha(0.f),
-    mContextConeFadeTime(0.f)
-{
-	mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
-	mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
-	mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
-}
-
-LLSetKeyBindDialog::~LLSetKeyBindDialog()
-{
-}
-
-//virtual
-BOOL LLSetKeyBindDialog::postBuild()
-{
-    childSetAction("SetEmpty", onBlank, this);
-    childSetAction("Default", onDefault, this);
-    childSetAction("Cancel", onCancel, this);
-    getChild<LLUICtrl>("Cancel")->setFocus(TRUE);
-
-    pCheckBox = getChild<LLCheckBoxCtrl>("apply_all");
-    pDesription = getChild<LLTextBase>("descritption");
-
-    gFocusMgr.setKeystrokesOnly(TRUE);
-
-    return TRUE;
-}
-
-//virtual
-void LLSetKeyBindDialog::onOpen(const LLSD& data)
-{
-     sRecordKeys = true;
-     LLModalDialog::onOpen(data);
-}
-
-//virtual
-void LLSetKeyBindDialog::onClose(bool app_quiting)
-{
-    sRecordKeys = false;
-    if (pParent)
-    {
-        pParent->onCancelKeyBind();
-        pParent = NULL;
-    }
-    if (pUpdater)
-    {
-        // Doubleclick timer has't fired, delete it
-        delete pUpdater;
-        pUpdater = NULL;
-    }
-    LLModalDialog::onClose(app_quiting);
-}
-
-void LLSetKeyBindDialog::drawFrustum()
-{
-    static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f);
-    drawConeToOwner(mContextConeOpacity, max_opacity, mFrustumOrigin.get(), mContextConeFadeTime, mContextConeInAlpha, mContextConeOutAlpha);
-}
-
-//virtual
-void LLSetKeyBindDialog::draw()
-{
-    drawFrustum();
-    LLModalDialog::draw();
-}
-
-void LLSetKeyBindDialog::setParent(LLKeyBindResponderInterface* parent, LLView* frustum_origin, U32 key_mask)
-{
-    pParent = parent;
-    mFrustumOrigin = frustum_origin->getHandle();
-    mKeyFilterMask = key_mask;
-
-    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");
-    }
-    pDesription->setText(getString("basic_description"));
-    pDesription->setTextArg("[INPUT]", input);
-}
-
-// static
-bool LLSetKeyBindDialog::recordKey(KEY key, MASK mask)
-{
-    if (sRecordKeys)
-    {
-        LLSetKeyBindDialog* dialog = LLFloaterReg::getTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD());
-        if (dialog && dialog->getVisible())
-        {
-            return dialog->recordAndHandleKey(key, mask);
-        }
-        else
-        {
-            LL_WARNS() << "Key recording was set despite no open dialog" << LL_ENDL;
-            sRecordKeys = false;
-        }
-    }
-    return false;
-}
-
-bool LLSetKeyBindDialog::recordAndHandleKey(KEY key, MASK mask)
-{
-    if ((key == 'Q' && mask == MASK_CONTROL)
-        || key == KEY_ESCAPE)
-    {
-        sRecordKeys = false;
-        closeFloater();
-        return true;
-    }
-
-    if (key == KEY_DELETE)
-    {
-        setKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
-        sRecordKeys = false;
-        closeFloater();
-        return false;
-    }
-
-    // forbidden keys
-    if (key == KEY_NONE
-        || key == KEY_RETURN
-        || key == KEY_BACKSPACE)
-    {
-        return false;
-    }
-
-    if ((mKeyFilterMask & ALLOW_MASKS) == 0
-        && (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT))
-    {
-        // mask by themself are not allowed
-        return false;
-    }
-    else if ((mKeyFilterMask & ALLOW_KEYS) == 0)
-    {
-        // basic keys not allowed
-        return false;
-    }
-    else if ((mKeyFilterMask & ALLOW_MASK_KEYS) == 0 && mask != 0)
-    {
-        // masked keys not allowed
-        return false;
-    }
-
-    if (LLKeyConflictHandler::isReservedByMenu(key, mask))
-    {
-        pDesription->setText(getString("reserved_by_menu"));
-        pDesription->setTextArg("[KEYSTR]", LLKeyboard::stringFromAccelerator(mask,key));
-        return true;
-    }
-
-    setKeyBind(CLICK_NONE, key, mask, pCheckBox->getValue().asBoolean());
-    sRecordKeys = false;
-    closeFloater();
-    return true;
-}
-
-BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down)
-{
-    BOOL result = FALSE;
-    if (!pParent)
-    {
-        // we already processed 'down' event, this is 'up', consume
-        closeFloater();
-        result = TRUE;
-    }
-    if (!result && clicktype == CLICK_LEFT)
-    {
-        // try handling buttons first
-        if (down)
-        {
-            result = LLView::handleMouseDown(x, y, mask);
-        }
-        else
-        {
-            result = LLView::handleMouseUp(x, y, mask);
-        }
-        if (result)
-        {
-            setFocus(TRUE);
-            gFocusMgr.setKeystrokesOnly(TRUE);
-        }
-        // ignore selection related combinations
-        else if (down && (mask & (MASK_SHIFT | MASK_CONTROL)) == 0)
-        {
-            // this can be a double click, wait a bit;
-            if (!pUpdater)
-            {
-                // Note: default doubleclick time is 500ms, but can stretch up to 5s
-                pUpdater = new Updater(boost::bind(&onClickTimeout, this, _1), 0.7f, mask);
-                result = TRUE;
-            }
-        }
-    }
-
-    if (!result
-        && (clicktype != CLICK_LEFT) // subcases were handled above
-        && ((mKeyFilterMask & ALLOW_MOUSE) != 0)
-        && (clicktype != CLICK_RIGHT || mask != 0) // reassigning menu button is not supported
-        && ((mKeyFilterMask & ALLOW_MASK_MOUSE) != 0 || mask == 0)) // reserved for selection
-    {
-        setKeyBind(clicktype, KEY_NONE, mask, pCheckBox->getValue().asBoolean());
-        result = TRUE;
-        if (!down)
-        {
-            // wait for 'up' event before closing
-            // alternative: set pUpdater
-            closeFloater();
-        }
-    }
-
-    return result;
-}
-
-//static
-void LLSetKeyBindDialog::onCancel(void* user_data)
-{
-    LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
-    self->closeFloater();
-}
-
-//static
-void LLSetKeyBindDialog::onBlank(void* user_data)
-{
-    LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
-    // tmp needs 'no key' button
-    self->setKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
-    self->closeFloater();
-}
-
-//static
-void LLSetKeyBindDialog::onDefault(void* user_data)
-{
-    LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
-    if (self->pParent)
-    {
-        self->pParent->onDefaultKeyBind(self->pCheckBox->getValue().asBoolean());
-        self->pParent = NULL;
-    }
-    self->closeFloater();
-}
-
-//static
-void LLSetKeyBindDialog::onClickTimeout(void* user_data, MASK mask)
-{
-    LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
-
-    // timer will delete itself after timeout
-    self->pUpdater = NULL;
-
-    self->setKeyBind(CLICK_LEFT, KEY_NONE, mask, self->pCheckBox->getValue().asBoolean());
-    self->closeFloater();
-}
-
-void LLSetKeyBindDialog::setKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes)
-{
-    if (pParent)
-    {
-        pParent->onSetKeyBind(click, key, mask, all_modes);
-        pParent = NULL;
-    }
-}
-
diff --git a/indra/newview/llsetkeybinddialog.h b/indra/newview/llsetkeybinddialog.h
deleted file mode 100644
index 70190230e4..0000000000
--- a/indra/newview/llsetkeybinddialog.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/** 
- * @file llsetkeybinddialog.h
- * @brief LLSetKeyBindDialog class definition
- *
- * $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_LLSETKEYBINDDIALOG_H
-#define LL_LLSETKEYBINDDIALOG_H
-
-#include "llmodaldialog.h"
-
-class LLCheckBoxCtrl;
-class LLTextBase;
-
-// 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 DEFAULT_KEY_FILTER = ALLOW_MOUSE | ALLOW_MASK_MOUSE | ALLOW_KEYS | ALLOW_MASK_KEYS;
-
-
-class LLKeyBindResponderInterface
-{
-public:
-    virtual ~LLKeyBindResponderInterface() {};
-
-    virtual void onCancelKeyBind() = 0;
-    virtual void onDefaultKeyBind(bool all_modes) = 0;
-    // returns true if parent failed to set key due to key being in use
-    virtual bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes) = 0;
-};
-
-class LLSetKeyBindDialog : public LLModalDialog
-{
-public:
-    LLSetKeyBindDialog(const LLSD& key);
-    ~LLSetKeyBindDialog();
-
-    /*virtual*/ BOOL postBuild();
-    /*virtual*/ void onOpen(const LLSD& data);
-    /*virtual*/ void onClose(bool app_quiting);
-    /*virtual*/ void draw();
-
-    void setParent(LLKeyBindResponderInterface* parent, LLView* frustum_origin, U32 key_mask = DEFAULT_KEY_FILTER);
-
-    // Wrapper around recordAndHandleKey
-    // It does not record, it handles, but handleKey function is already in use
-    static bool recordKey(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);
-    static void onClickTimeout(void* user_data, MASK mask);
-
-    class Updater;
-
-private:
-    bool recordAndHandleKey(KEY key, MASK mask);
-    void setKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes);
-    LLKeyBindResponderInterface *pParent;
-    LLCheckBoxCtrl *pCheckBox;
-    LLTextBase *pDesription;
-
-    U32 mKeyFilterMask;
-    Updater *pUpdater;
-
-    static bool sRecordKeys; // for convinience and not to check instance each time
-
-    // drawFrustum
-private:
-    void drawFrustum();
-
-    LLHandle <LLView>   mFrustumOrigin;
-    F32                 mContextConeOpacity;
-    F32                 mContextConeInAlpha;
-    F32                 mContextConeOutAlpha;
-    F32                 mContextConeFadeTime;
-};
-
-
-#endif  // LL_LLSETKEYBINDDIALOG_H
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index be8a9a5d2d..77bbcdada6 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -994,7 +994,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/lltool.cpp b/indra/newview/lltool.cpp
index 5235914c34..c5e31ff8e6 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, EMouseClickType clicktype, BOOL down)
+BOOL LLTool::handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down)
 {
 	BOOL result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down);
 	
@@ -83,9 +83,9 @@ BOOL LLTool::handleMouseDown(S32 x, S32 y, MASK mask)
 		LL_INFOS() << "LLTool left mouse down" << LL_ENDL;
 	}
 	// by default, didn't handle it
-	// AGENT_CONTROL_LBUTTON_DOWN is handled by scanMouse() and scanKey()
 	// LL_INFOS() << "LLTool::handleMouseDown" << LL_ENDL;
-	return FALSE;
+	gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN);
+	return TRUE;
 }
 
 BOOL LLTool::handleMouseUp(S32 x, S32 y, MASK mask)
@@ -95,8 +95,8 @@ BOOL LLTool::handleMouseUp(S32 x, S32 y, MASK mask)
 		LL_INFOS() << "LLTool left mouse up" << LL_ENDL;
 	}
 	// by default, didn't handle it
-	// AGENT_CONTROL_LBUTTON_UP is handled by scanMouse() and scanKey()
 	// LL_INFOS() << "LLTool::handleMouseUp" << LL_ENDL;
+	gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP);
 	return TRUE;
 }
 
diff --git a/indra/newview/lltool.h b/indra/newview/lltool.h
index 41a38804ce..308983afda 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, EMouseClickType clicktype, BOOL down);
+	virtual BOOL	handleAnyMouseClick(S32 x, S32 y, MASK mask, LLMouseHandler::EClickType 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 0839ea6cf5..aeb8bdc496 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -83,6 +83,7 @@ LLToolPie::LLToolPie()
 	mMouseOutsideSlop( false ),
 	mMouseSteerX(-1),
 	mMouseSteerY(-1),
+	mBlockClickToWalk(false),
 	mClickAction(0),
 	mClickActionBuyEnabled( gSavedSettings.getBOOL("ClickActionBuyEnabled") ),
 	mClickActionPayEnabled( gSavedSettings.getBOOL("ClickActionPayEnabled") ),
@@ -90,7 +91,7 @@ LLToolPie::LLToolPie()
 {
 }
 
-BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down)
+BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down)
 {
 	BOOL result = LLMouseHandler::handleAnyMouseClick(x, y, mask, clicktype, down);
 	
@@ -171,8 +172,10 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)
 	mPick.mKeyMask = mask;
 
 	mMouseButtonDown = true;
+	
+	handleLeftClickPick();
 
-    return handleLeftClickPick();
+	return TRUE;
 }
 
 // Spawn context menus on right mouse down so you can drag over and select
@@ -371,6 +374,8 @@ BOOL LLToolPie::handleLeftClickPick()
 	// put focus back "in world"
 	if (gFocusMgr.getKeyboardFocus())
 	{
+		// don't click to walk on attempt to give focus to world
+		mBlockClickToWalk = true;
 		gFocusMgr.setKeyboardFocus(NULL);
 	}
 
@@ -414,7 +419,7 @@ BOOL LLToolPie::handleLeftClickPick()
 		}
 		object = (LLViewerObject*)object->getParent();
 	}
-	if (object && object == gAgentAvatarp)
+	if (object && object == gAgentAvatarp && !gSavedSettings.getBOOL("ClickToWalk"))
 	{
 		// we left clicked on avatar, switch to focus mode
 		mMouseButtonDown = false;
@@ -431,6 +436,7 @@ BOOL LLToolPie::handleLeftClickPick()
 	//	LLFirstUse::useLeftClickNoHit();
 	/////////
 
+	// Eat the event
 	return LLTool::handleMouseDown(x, y, mask);
 }
 
@@ -537,120 +543,17 @@ void LLToolPie::resetSelection()
 	mClickAction = 0;
 }
 
-bool LLToolPie::walkToClickedLocation()
+void LLToolPie::walkToClickedLocation()
 {
-    if (gAgent.getFlying()							// don't auto-navigate while flying until that works
-        || !gAgentAvatarp
-        || gAgentAvatarp->isSitting())
-    {
-        return false;
-    }
-
-    LLPickInfo saved_pick = mPick;
-    if (gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK)
-    {
-        mPick = gViewerWindow->pickImmediate(mHoverPick.mMousePt.mX, mHoverPick.mMousePt.mY,
-            FALSE /* ignore transparent */,
-            FALSE /* ignore rigged */,
-            FALSE /* ignore particles */);
-    }
-    else
-    {
-        // We do not handle hover in mouselook as we do in other modes, so
-        // use croshair's position to do a pick
-        mPick = gViewerWindow->pickImmediate(gViewerWindow->getWorldViewRectScaled().getWidth() / 2,
-            gViewerWindow->getWorldViewRectScaled().getHeight() / 2,
-            FALSE /* ignore transparent */,
-            FALSE /* ignore rigged */,
-            FALSE /* ignore particles */);
-    }
-
-    if (mPick.mPickType == LLPickInfo::PICK_OBJECT)
-    {
-        if (mPick.getObject() && mPick.getObject()->isHUDAttachment())
-        {
-            mPick = saved_pick;
-            return false;
-        }
-    }
-
-    LLViewerObject* avatar_object = mPick.getObject();
-
-    // get pointer to avatar
-    while (avatar_object && !avatar_object->isAvatar())
-    {
-        avatar_object = (LLViewerObject*)avatar_object->getParent();
-    }
-
-    if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf())
-    {
-        const F64 SELF_CLICK_WALK_DISTANCE = 3.0;
-        // pretend we picked some point a bit in front of avatar
-        mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE;
-    }
-
-    if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) ||
-        (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero()))
-    {
-        gAgentCamera.setFocusOnAvatar(TRUE, TRUE);
-
-        if (mAutoPilotDestination) { mAutoPilotDestination->markDead(); }
-        mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE);
-        mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal);
-        mAutoPilotDestination->setPixelSize(5);
-        mAutoPilotDestination->setColor(LLColor4U(170, 210, 190));
-        mAutoPilotDestination->setDuration(3.f);
-
-        LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal;
-        gAgent.startAutoPilotGlobal(pos, std::string(), NULL, NULL, NULL, 0.f, 0.03f, FALSE);
-        LLFirstUse::notMoving(false);
-        showVisualContextMenuEffect();
-        return true;
-    }
-    else
-    {
-        LL_DEBUGS() << "walk target was "
-            << (mPick.mPosGlobal.isExactlyZero() ? "zero" : "not zero")
-            << ", pick type was " << (mPick.mPickType == LLPickInfo::PICK_LAND ? "land" : "not land")
-            << ", pick object was " << mPick.mObjectID
-            << LL_ENDL;
-        mPick = saved_pick;
-        return false;
-    }
-    return true;
-}
-
-bool LLToolPie::teleportToClickedLocation()
-{
-    if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK)
-    {
-        // We do not handle hover in mouselook as we do in other modes, so
-        // use croshair's position to do a pick
-        BOOL pick_rigged = false;
-        mHoverPick = gViewerWindow->pickImmediate(gViewerWindow->getWorldViewRectScaled().getWidth() / 2,
-                                                  gViewerWindow->getWorldViewRectScaled().getHeight() / 2,
-                                                  FALSE,
-                                                  pick_rigged);
-    }
-    LLViewerObject* objp = mHoverPick.getObject();
-    LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL;
-
-    bool is_in_world = mHoverPick.mObjectID.notNull() && objp && !objp->isHUDAttachment();
-    bool is_land = mHoverPick.mPickType == LLPickInfo::PICK_LAND;
-    bool pos_non_zero = !mHoverPick.mPosGlobal.isExactlyZero();
-    bool has_touch_handler = (objp && objp->flagHandleTouch()) || (parentp && parentp->flagHandleTouch());
-    bool has_click_action = final_click_action(objp);
-
-    if (pos_non_zero && (is_land || (is_in_world && !has_touch_handler && !has_click_action)))
-    {
-        LLVector3d pos = mHoverPick.mPosGlobal;
-        pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot();
-        gAgent.teleportViaLocationLookAt(pos);
-        mPick = mHoverPick;
-        showVisualContextMenuEffect();
-        return true;
-    }
-    return false;
+	if(mAutoPilotDestination) { mAutoPilotDestination->markDead(); }
+	mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE);
+	mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal);
+	mAutoPilotDestination->setPixelSize(5);
+	mAutoPilotDestination->setColor(LLColor4U(170, 210, 190));
+	mAutoPilotDestination->setDuration(3.f);
+
+	LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal;
+	gAgent.startAutoPilotGlobal(pos, std::string(), NULL, NULL, NULL, 0.f, 0.03f, FALSE);
 }
 
 // When we get object properties after left-clicking on an object
@@ -726,7 +629,8 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
 		LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL;
 	}
 	else if (!mMouseOutsideSlop 
-		&& mMouseButtonDown)
+		&& mMouseButtonDown 
+		&& gSavedSettings.getBOOL("ClickToWalk"))
 	{
 		S32 delta_x = x - mMouseDownX;
 		S32 delta_y = y - mMouseDownY;
@@ -811,10 +715,70 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
         mDoubleClickTimer.reset();
     }
     LLViewerObject* obj = mPick.getObject();
+	U8 click_action = final_click_action(obj);
 
+	// let media have first pass at click
+	if (handleMediaMouseUp() || LLViewerMediaFocus::getInstance()->getFocus())
+	{
+		mBlockClickToWalk = true;
+	}
 	stopCameraSteering();
 	mMouseButtonDown = false;
 
+	if (click_action == CLICK_ACTION_NONE				// not doing 1-click action
+		&& gSavedSettings.getBOOL("ClickToWalk")		// click to walk enabled
+		&& !gAgent.getFlying()							// don't auto-navigate while flying until that works
+		&& gAgentAvatarp
+		&& !gAgentAvatarp->isSitting()
+		&& !mBlockClickToWalk							// another behavior hasn't cancelled click to walk
+        )
+	{
+        // We may be doing click to walk, but we don't want to use a target on
+        // a transparent object because the user thought they were clicking on
+        // whatever they were seeing through it, so recompute what was clicked on
+        // ignoring transparent objects
+        LLPickInfo savedPick = mPick;
+        mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY,
+                                             FALSE /* ignore transparent */,
+                                             FALSE /* ignore rigged */,
+                                             FALSE /* ignore particles */);
+
+        if (!mPick.mPosGlobal.isExactlyZero()			// valid coordinates for pick
+            && (mPick.mPickType == LLPickInfo::PICK_LAND	// we clicked on land
+                || mPick.mObjectID.notNull()))				// or on an object
+        {
+            // handle special cases of steering picks
+            LLViewerObject* avatar_object = mPick.getObject();
+
+            // get pointer to avatar
+            while (avatar_object && !avatar_object->isAvatar())
+            {
+                avatar_object = (LLViewerObject*)avatar_object->getParent();
+            }
+
+            if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf())
+            {
+                const F64 SELF_CLICK_WALK_DISTANCE = 3.0;
+                // pretend we picked some point a bit in front of avatar
+                mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE;
+            }
+            gAgentCamera.setFocusOnAvatar(TRUE, TRUE);
+            walkToClickedLocation();
+            LLFirstUse::notMoving(false);
+
+            return TRUE;
+        }
+        else
+        {
+            LL_DEBUGS("maint5901") << "walk target was "
+                                   << (mPick.mPosGlobal.isExactlyZero() ? "zero" : "not zero")
+                                   << ", pick type was " << (mPick.mPickType == LLPickInfo::PICK_LAND ? "land" : "not land")
+                                   << ", pick object was " << mPick.mObjectID
+                                   << LL_ENDL;
+            // we didn't click to walk, so restore the original target
+            mPick = savedPick;
+        }
+	}
 	gViewerWindow->setCursor(UI_CURSOR_ARROW);
 	if (hasMouseCapture())
 	{
@@ -824,6 +788,7 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
 	LLToolMgr::getInstance()->clearTransientTool();
 	gAgentCamera.setLookAt(LOOKAT_TARGET_CONVERSATION, obj); // maybe look at object/person clicked on
 
+	mBlockClickToWalk = false;
 	return LLTool::handleMouseUp(x, y, mask);
 }
 
@@ -849,13 +814,66 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask)
 		return TRUE;
 	}
     
-	if (!mDoubleClickTimer.getStarted() || (mDoubleClickTimer.getElapsedTimeF32() > 0.3f))
+    	if (!mDoubleClickTimer.getStarted() || (mDoubleClickTimer.getElapsedTimeF32() > 0.3f))
 	{
 		mDoubleClickTimer.stop();
 		return FALSE;
 	}
 	mDoubleClickTimer.stop();
 
+	if (gSavedSettings.getBOOL("DoubleClickAutoPilot"))
+	{
+        // We may be doing double click to walk, but we don't want to use a target on
+        // a transparent object because the user thought they were clicking on
+        // whatever they were seeing through it, so recompute what was clicked on
+        // ignoring transparent objects
+        LLPickInfo savedPick = mPick;
+        mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY,
+                                             FALSE /* ignore transparent */,
+                                             FALSE /* ignore rigged */,
+                                             FALSE /* ignore particles */);
+
+        if(mPick.mPickType == LLPickInfo::PICK_OBJECT)
+        {
+            if (mPick.getObject() && mPick.getObject()->isHUDAttachment())
+            {
+                mPick = savedPick;
+                return FALSE;
+            }
+        }
+
+		if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) ||
+			(mPick.mObjectID.notNull()  && !mPick.mPosGlobal.isExactlyZero()))
+		{
+			walkToClickedLocation();
+			return TRUE;
+		}
+        else
+        {
+            // restore the original pick for any other purpose
+            mPick = savedPick;
+        }
+	}
+	else if (gSavedSettings.getBOOL("DoubleClickTeleport"))
+	{
+		LLViewerObject* objp = mPick.getObject();
+		LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL;
+
+		bool is_in_world = mPick.mObjectID.notNull() && objp && !objp->isHUDAttachment();
+		bool is_land = mPick.mPickType == LLPickInfo::PICK_LAND;
+		bool pos_non_zero = !mPick.mPosGlobal.isExactlyZero();
+		bool has_touch_handler = (objp && objp->flagHandleTouch()) || (parentp && parentp->flagHandleTouch());
+		bool has_click_action = final_click_action(objp);
+
+		if (pos_non_zero && (is_land || (is_in_world && !has_touch_handler && !has_click_action)))
+		{
+			LLVector3d pos = mPick.mPosGlobal;
+			pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot();
+			gAgent.teleportViaLocationLookAt(pos);
+			return TRUE;
+		}
+	}
+
 	return FALSE;
 }
 
@@ -1387,6 +1405,7 @@ void LLToolPie::VisitHomePage(const LLPickInfo& info)
 void LLToolPie::handleSelect()
 {
 	// tool is reselected when app gets focus, etc.
+	mBlockClickToWalk = true;	
 }
 
 void LLToolPie::handleDeselect()
@@ -1447,7 +1466,7 @@ void LLToolPie::stopCameraSteering()
 
 bool LLToolPie::inCameraSteerMode()
 {
-	return mMouseButtonDown && mMouseOutsideSlop;
+	return mMouseButtonDown && mMouseOutsideSlop && gSavedSettings.getBOOL("ClickToWalk");
 }
 
 // true if x,y outside small box around start_x,start_y
@@ -1898,6 +1917,7 @@ void LLToolPie::startCameraSteering()
 {
 	LLFirstUse::notMoving(false);
 	mMouseOutsideSlop = true;
+	mBlockClickToWalk = true;
 
 	if (gAgentCamera.getFocusOnAvatar())
 	{
diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h
index ac6751aac0..fe0acfe473 100644
--- a/indra/newview/lltoolpie.h
+++ b/indra/newview/lltoolpie.h
@@ -42,7 +42,7 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie>
 public:
 
 	// Virtual functions inherited from LLMouseHandler
-	virtual BOOL		handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down);
+	virtual BOOL		handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType 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);
@@ -67,8 +67,8 @@ public:
 	LLViewerObject*		getClickActionObject() { return mClickActionObject; }
 	LLObjectSelection*	getLeftClickSelection() { return (LLObjectSelection*)mLeftClickSelection; }
 	void 				resetSelection();
-	bool				walkToClickedLocation();
-	bool				teleportToClickedLocation();
+	void				walkToClickedLocation();
+	void				blockClickToWalk() { mBlockClickToWalk = true; }
 	void				stopClickToWalk();
 	
 	static void			selectionPropertiesReceived();
@@ -110,6 +110,7 @@ private:
 	LLPointer<LLHUDEffectBlob>	mAutoPilotDestination;
 	LLPointer<LLHUDEffectBlob>	mMouseSteerGrabPoint;
 	bool				mClockwise;			
+	bool				mBlockClickToWalk;
 	LLUUID				mMediaMouseCaptureID;
 	LLPickInfo			mPick;
 	LLPickInfo			mHoverPick;
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
deleted file mode 100644
index ad4b9d4215..0000000000
--- a/indra/newview/llviewerinput.cpp
+++ /dev/null
@@ -1,1528 +0,0 @@
-/** 
- * @file llviewerinput.cpp
- * @brief LLViewerInput class implementation
- *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llviewerinput.h"
-
-#include "llappviewer.h"
-#include "llfloaterreg.h"
-#include "llmath.h"
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "llfloaterimnearbychat.h"
-#include "llfocusmgr.h"
-#include "llkeybind.h" // LLKeyData
-#include "llmorphview.h"
-#include "llmoveview.h"
-#include "lltoolfocus.h"
-#include "lltoolpie.h"
-#include "llviewercontrol.h"
-#include "llviewerwindow.h"
-#include "llvoavatarself.h"
-#include "llfloatercamera.h"
-#include "llinitparam.h"
-#include "llselectmgr.h"
-
-//
-// Constants
-//
-
-const F32 FLY_TIME = 0.5f;
-const F32 FLY_FRAMES = 4;
-
-const F32 NUDGE_TIME = 0.25f;  // in seconds
-const S32 NUDGE_FRAMES = 2;
-const F32 ORBIT_NUDGE_RATE = 0.05f;  // fraction of normal speed
-
-const LLKeyData agent_control_lbutton(CLICK_LEFT, KEY_NONE, MASK_NONE, true);
-
-struct LLKeyboardActionRegistry 
-:	public LLRegistrySingleton<std::string, boost::function<bool (EKeystate keystate)>, LLKeyboardActionRegistry>
-{
-	LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry);
-};
-
-LLViewerInput gViewerInput;
-
-bool agent_jump( EKeystate s )
-{
-	static BOOL first_fly_attempt(TRUE);
-	if (KEYSTATE_UP == s)
-	{
-		first_fly_attempt = TRUE;
-		return true;
-	}
-	F32 time = gKeyboard->getCurKeyElapsedTime();
-	S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
-
-	if( time < FLY_TIME 
-		|| frame_count <= FLY_FRAMES 
-		|| gAgent.upGrabbed()
-		|| !gSavedSettings.getBOOL("AutomaticFly"))
-	{
-		gAgent.moveUp(1);
-	}
-	else
-	{
-		gAgent.setFlying(TRUE, first_fly_attempt);
-		first_fly_attempt = FALSE;
-		gAgent.moveUp(1);
-	}
-	return true;
-}
-
-bool agent_push_down( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgent.moveUp(-1);
-	return true;
-}
-
-static void agent_check_temporary_run(LLAgent::EDoubleTapRunMode mode)
-{
-	if (gAgent.mDoubleTapRunMode == mode &&
-		gAgent.getRunning() &&
-		!gAgent.getAlwaysRun())
-	{
-		// Turn off temporary running.
-		gAgent.clearRunning();
-		gAgent.sendWalkRun(gAgent.getRunning());
-	}
-}
-
-static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode mode)
-{
-	if (KEYSTATE_UP == s)
-	{
-		// Note: in case shift is already released, slide left/right run
-		// will be released in agent_turn_left()/agent_turn_right()
-		agent_check_temporary_run(mode);
-	}
-	else if (gSavedSettings.getBOOL("AllowTapTapHoldRun") &&
-		 KEYSTATE_DOWN == s &&
-		 !gAgent.getRunning())
-	{
-		if (gAgent.mDoubleTapRunMode == mode &&
-		    gAgent.mDoubleTapRunTimer.getElapsedTimeF32() < NUDGE_TIME)
-		{
-			// Same walk-key was pushed again quickly; this is a
-			// double-tap so engage temporary running.
-			gAgent.setRunning();
-			gAgent.sendWalkRun(gAgent.getRunning());
-		}
-
-		// Pressing any walk-key resets the double-tap timer
-		gAgent.mDoubleTapRunTimer.reset();
-		gAgent.mDoubleTapRunMode = mode;
-	}
-}
-
-static void agent_push_forwardbackward( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode )
-{
-	agent_handle_doubletap_run(s, mode);
-	if (KEYSTATE_UP == s) return;
-
-	F32 time = gKeyboard->getCurKeyElapsedTime();
-	S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
-
-	if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES)
-	{
-		gAgent.moveAtNudge(direction);
-	}
-	else
-	{
-		gAgent.moveAt(direction);
-	}
-}
-
-bool camera_move_forward( EKeystate s );
-
-bool agent_push_forward( EKeystate s )
-{
-	if(gAgent.isMovementLocked()) return true;
-
-	//in free camera control mode we need to intercept keyboard events for avatar movements
-	if (LLFloaterCamera::inFreeCameraMode())
-	{
-		camera_move_forward(s);
-	}
-	else
-	{
-		agent_push_forwardbackward(s, 1, LLAgent::DOUBLETAP_FORWARD);
-	}
-	return true;
-}
-
-bool camera_move_backward( EKeystate s );
-
-bool agent_push_backward( EKeystate s )
-{
-	if(gAgent.isMovementLocked()) return true;
-
-	//in free camera control mode we need to intercept keyboard events for avatar movements
-	if (LLFloaterCamera::inFreeCameraMode())
-	{
-		camera_move_backward(s);
-	}
-	else if (!gAgent.backwardGrabbed() && gAgentAvatarp->isSitting() && gSavedSettings.getBOOL("LeaveMouselook"))
-	{
-		gAgentCamera.changeCameraToThirdPerson();
-	}
-	else
-	{
-		agent_push_forwardbackward(s, -1, LLAgent::DOUBLETAP_BACKWARD);
-	}
-	return true;
-}
-
-static void agent_slide_leftright( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode )
-{
-	agent_handle_doubletap_run(s, mode);
-	if( KEYSTATE_UP == s ) return;
-	F32 time = gKeyboard->getCurKeyElapsedTime();
-	S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
-
-	if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES)
-	{
-		gAgent.moveLeftNudge(direction);
-	}
-	else
-	{
-		gAgent.moveLeft(direction);
-	}
-}
-
-
-bool agent_slide_left( EKeystate s )
-{
-	if(gAgent.isMovementLocked()) return true;
-	agent_slide_leftright(s, 1, LLAgent::DOUBLETAP_SLIDELEFT);
-	return true;
-}
-
-
-bool agent_slide_right( EKeystate s )
-{
-	if(gAgent.isMovementLocked()) return true;
-	agent_slide_leftright(s, -1, LLAgent::DOUBLETAP_SLIDERIGHT);
-	return true;
-}
-
-bool camera_spin_around_cw( EKeystate s );
-
-bool agent_turn_left(EKeystate s)
-{
-	//in free camera control mode we need to intercept keyboard events for avatar movements
-	if (LLFloaterCamera::inFreeCameraMode())
-	{
-		camera_spin_around_cw(s);
-		return true;
-	}
-
-	if(gAgent.isMovementLocked()) return false;
-
-	if (LLToolCamera::getInstance()->mouseSteerMode())
-	{
-		agent_slide_left(s);
-	}
-	else
-	{
-		if (KEYSTATE_UP == s)
-		{
-			// Check temporary running. In case user released 'left' key with shift already released.
-			agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDELEFT);
-			return true;
-		}
-		F32 time = gKeyboard->getCurKeyElapsedTime();
-		gAgent.moveYaw( LLFloaterMove::getYawRate( time ) );
-	}
-	return true;
-}
-
-bool camera_spin_around_ccw( EKeystate s );
-
-bool agent_turn_right( EKeystate s )
-{
-	//in free camera control mode we need to intercept keyboard events for avatar movements
-	if (LLFloaterCamera::inFreeCameraMode())
-	{
-		camera_spin_around_ccw(s);
-		return true;
-	}
-
-	if(gAgent.isMovementLocked()) return false;
-
-	if (LLToolCamera::getInstance()->mouseSteerMode())
-	{
-		agent_slide_right(s);
-	}
-	else
-	{
-		if (KEYSTATE_UP == s)
-		{
-			// Check temporary running. In case user released 'right' key with shift already released.
-			agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDERIGHT);
-			return true;
-		}
-		F32 time = gKeyboard->getCurKeyElapsedTime();
-		gAgent.moveYaw( -LLFloaterMove::getYawRate( time ) );
-	}
-	return true;
-}
-
-bool agent_look_up( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgent.movePitch(-1);
-	//gAgent.rotate(-2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
-	return true;
-}
-
-
-bool agent_look_down( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgent.movePitch(1);
-	//gAgent.rotate(2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
-	return true;
-}
-
-bool agent_toggle_fly( EKeystate s )
-{
-	// Only catch the edge
-	if (KEYSTATE_DOWN == s )
-	{
-		LLAgent::toggleFlying();
-	}
-	return true;
-}
-
-F32 get_orbit_rate()
-{
-	F32 time = gKeyboard->getCurKeyElapsedTime();
-	if( time < NUDGE_TIME )
-	{
-		F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME;
-		//LL_INFOS() << rate << LL_ENDL;
-		return rate;
-	}
-	else
-	{
-		return 1;
-	}
-}
-
-bool camera_spin_around_ccw( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
-	return true;
-}
-
-
-bool camera_spin_around_cw( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setOrbitRightKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_spin_around_ccw_sitting( EKeystate s )
-{
-	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT ) return true;
-	if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning())
-	{
-		//send keystrokes, but do not change camera
-		agent_turn_right(s);
-	}
-	else
-	{
-		//change camera but do not send keystrokes
-		gAgentCamera.unlockView();
-		gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
-	}
-	return true;
-}
-
-
-bool camera_spin_around_cw_sitting( EKeystate s )
-{
-	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT ) return true;
-	if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning())
-	{
-		//send keystrokes, but do not change camera
-		agent_turn_left(s);
-	}
-	else
-	{
-		//change camera but do not send keystrokes
-		gAgentCamera.unlockView();
-		gAgentCamera.setOrbitRightKey( get_orbit_rate() );
-	}
-	return true;
-}
-
-
-bool camera_spin_over( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setOrbitUpKey( get_orbit_rate() );
-	return true;
-}
-
-
-bool camera_spin_under( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setOrbitDownKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_spin_over_sitting( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	if (gAgent.upGrabbed() || gAgentCamera.sitCameraEnabled())
-	{
-		//send keystrokes, but do not change camera
-		agent_jump(s);
-	}
-	else
-	{
-		//change camera but do not send keystrokes
-		gAgentCamera.setOrbitUpKey( get_orbit_rate() );
-	}
-	return true;
-}
-
-
-bool camera_spin_under_sitting( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	if (gAgent.downGrabbed() || gAgentCamera.sitCameraEnabled())
-	{
-		//send keystrokes, but do not change camera
-		agent_push_down(s);
-	}
-	else
-	{
-		//change camera but do not send keystrokes
-		gAgentCamera.setOrbitDownKey( get_orbit_rate() );
-	}
-	return true;
-}
-
-bool camera_move_forward( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setOrbitInKey( get_orbit_rate() );
-	return true;
-}
-
-
-bool camera_move_backward( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setOrbitOutKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_move_forward_sitting( EKeystate s )
-{
-	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD ) return true;
-	if (gAgent.forwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun()))
-	{
-		agent_push_forward(s);
-	}
-	else
-	{
-		gAgentCamera.setOrbitInKey( get_orbit_rate() );
-	}
-	return true;
-}
-
-bool camera_move_backward_sitting( EKeystate s )
-{
-	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD ) return true;
-
-	if (gAgent.backwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun()))
-	{
-		agent_push_backward(s);
-	}
-	else
-	{
-		gAgentCamera.setOrbitOutKey( get_orbit_rate() );
-	}
-	return true;
-}
-
-bool camera_pan_up( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setPanUpKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_pan_down( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setPanDownKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_pan_left( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setPanLeftKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_pan_right( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setPanRightKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_pan_in( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setPanInKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_pan_out( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setPanOutKey( get_orbit_rate() );
-	return true;
-}
-
-bool camera_move_forward_fast( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setOrbitInKey(2.5f);
-	return true;
-}
-
-bool camera_move_backward_fast( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gAgentCamera.unlockView();
-	gAgentCamera.setOrbitOutKey(2.5f);
-	return true;
-}
-
-
-bool edit_avatar_spin_ccw( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gMorphView->setCameraDrivenByKeys( TRUE );
-	gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
-	//gMorphView->orbitLeft( get_orbit_rate() );
-	return true;
-}
-
-
-bool edit_avatar_spin_cw( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gMorphView->setCameraDrivenByKeys( TRUE );
-	gAgentCamera.setOrbitRightKey( get_orbit_rate() );
-	//gMorphView->orbitRight( get_orbit_rate() );
-	return true;
-}
-
-bool edit_avatar_spin_over( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gMorphView->setCameraDrivenByKeys( TRUE );
-	gAgentCamera.setOrbitUpKey( get_orbit_rate() );
-	//gMorphView->orbitUp( get_orbit_rate() );
-	return true;
-}
-
-
-bool edit_avatar_spin_under( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gMorphView->setCameraDrivenByKeys( TRUE );
-	gAgentCamera.setOrbitDownKey( get_orbit_rate() );
-	//gMorphView->orbitDown( get_orbit_rate() );
-	return true;
-}
-
-bool edit_avatar_move_forward( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gMorphView->setCameraDrivenByKeys( TRUE );
-	gAgentCamera.setOrbitInKey( get_orbit_rate() );
-	//gMorphView->orbitIn();
-	return true;
-}
-
-
-bool edit_avatar_move_backward( EKeystate s )
-{
-	if( KEYSTATE_UP == s  ) return true;
-	gMorphView->setCameraDrivenByKeys( TRUE );
-	gAgentCamera.setOrbitOutKey( get_orbit_rate() );
-	//gMorphView->orbitOut();
-	return true;
-}
-
-bool stop_moving( EKeystate s )
-{
-	if( KEYSTATE_DOWN != s  ) return true;
-	// stop agent
-	gAgent.setControlFlags(AGENT_CONTROL_STOP);
-
-	// cancel autopilot
-	gAgent.stopAutoPilot();
-	return true;
-}
-
-bool start_chat( EKeystate s )
-{
-    if (LLAppViewer::instance()->quitRequested())
-    {
-        return true; // can't talk, gotta go, kthxbye!
-    }
-    if (KEYSTATE_DOWN != s) return true;
-
-	// start chat
-	LLFloaterIMNearbyChat::startChat(NULL);
-	return true;
-}
-
-bool start_gesture( EKeystate s )
-{
-	LLUICtrl* focus_ctrlp = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
-	if (KEYSTATE_UP == s &&
-		! (focus_ctrlp && focus_ctrlp->acceptsTextInput()))
-	{
- 		if ((LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"))->getCurrentChat().empty())
- 		{
- 			// No existing chat in chat editor, insert '/'
- 			LLFloaterIMNearbyChat::startChat("/");
- 		}
- 		else
- 		{
- 			// Don't overwrite existing text in chat editor
- 			LLFloaterIMNearbyChat::startChat(NULL);
- 		}
-	}
-	return true;
-}
-
-bool run_forward(EKeystate s)
-{
-    if (KEYSTATE_UP != s)
-    {
-        if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD)
-        {
-            gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_FORWARD;
-        }
-        if (!gAgent.getRunning())
-        {
-            gAgent.setRunning();
-            gAgent.sendWalkRun(true);
-        }
-    }
-    else if(KEYSTATE_UP == s)
-    {
-        if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_FORWARD)
-            gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE;
-        gAgent.clearRunning();
-        gAgent.sendWalkRun(false);
-    }
-    agent_push_forward(s);
-    return true;
-}
-
-bool run_backward(EKeystate s)
-{
-    if (KEYSTATE_UP != s)
-    {
-        if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD)
-        {
-            gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_BACKWARD;
-        }
-        if (!gAgent.getRunning())
-        {
-            gAgent.setRunning();
-            gAgent.sendWalkRun(true);
-        }
-    }
-    else if (KEYSTATE_UP == s)
-    {
-        if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_BACKWARD)
-            gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE;
-        gAgent.clearRunning();
-        gAgent.sendWalkRun(false);
-    }
-    agent_push_backward(s);
-    return true;
-}
-
-bool run_left(EKeystate s)
-{
-    if (KEYSTATE_UP != s)
-    {
-        if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT)
-        {
-            gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_SLIDELEFT;
-        }
-        if (!gAgent.getRunning())
-        {
-            gAgent.setRunning();
-            gAgent.sendWalkRun(true);
-        }
-    }
-    else if (KEYSTATE_UP == s)
-    {
-        if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_SLIDELEFT)
-            gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE;
-        gAgent.clearRunning();
-        gAgent.sendWalkRun(false);
-    }
-    agent_slide_left(s);
-    return true;
-}
-
-bool run_right(EKeystate s)
-{
-    if (KEYSTATE_UP != s)
-    {
-        if (gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT)
-        {
-            gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_SLIDERIGHT;
-        }
-        if (!gAgent.getRunning())
-        {
-            gAgent.setRunning();
-            gAgent.sendWalkRun(true);
-        }
-    }
-    else if (KEYSTATE_UP == s)
-    {
-        if (gAgent.mDoubleTapRunMode == LLAgent::DOUBLETAP_SLIDERIGHT)
-            gAgent.mDoubleTapRunMode = LLAgent::DOUBLETAP_NONE;
-        gAgent.clearRunning();
-        gAgent.sendWalkRun(false);
-    }
-    agent_slide_right(s);
-    return true;
-}
-
-bool toggle_run(EKeystate s)
-{
-    if (KEYSTATE_DOWN != s) return true;
-    bool run = gAgent.getAlwaysRun();
-    if (run)
-    {
-        gAgent.clearAlwaysRun();
-        gAgent.clearRunning();
-    }
-    else
-    {
-        gAgent.setAlwaysRun();
-        gAgent.setRunning();
-    }
-    gAgent.sendWalkRun(!run);
-	return true;
-}
-
-bool toggle_sit(EKeystate s)
-{
-    if (KEYSTATE_DOWN != s) return true;
-    if (gAgent.isSitting())
-    {
-        gAgent.standUp();
-    }
-    else
-    {
-        gAgent.sitDown();
-    }
-	return true;
-}
-
-bool toggle_pause_media(EKeystate s) // analogue of play/pause button in top bar
-{
-    if (KEYSTATE_DOWN != s) return true;
-    bool pause = LLViewerMedia::getInstance()->isAnyMediaPlaying();
-    LLViewerMedia::getInstance()->setAllMediaPaused(pause);
-    return true;
-}
-
-bool toggle_enable_media(EKeystate s)
-{
-    if (KEYSTATE_DOWN != s) return true;
-    bool pause = LLViewerMedia::getInstance()->isAnyMediaPlaying() || LLViewerMedia::getInstance()->isAnyMediaShowing();
-    LLViewerMedia::getInstance()->setAllMediaEnabled(!pause);
-    return true;
-}
-
-bool walk_to(EKeystate s)
-{
-    if (KEYSTATE_DOWN != s) return true;
-    return LLToolPie::getInstance()->walkToClickedLocation();
-}
-
-bool teleport_to(EKeystate s)
-{
-    if (KEYSTATE_DOWN != s) return true;
-    return LLToolPie::getInstance()->teleportToClickedLocation();
-}
-
-bool toggle_voice(EKeystate s)
-{
-    if (KEYSTATE_DOWN != s) return true;
-    if (!LLAgent::isActionAllowed("speak")) return false;
-    LLVoiceClient::getInstance()->toggleUserPTTState();
-    return true;
-}
-
-bool voice_follow_key(EKeystate s)
-{
-    if (KEYSTATE_DOWN == s)
-    {
-        if (!LLAgent::isActionAllowed("speak")) return false;
-        LLVoiceClient::getInstance()->setUserPTTState(true);
-        return true;
-    }
-    else if (KEYSTATE_UP == s && LLVoiceClient::getInstance()->getUserPTTState())
-    {
-        LLVoiceClient::getInstance()->setUserPTTState(false);
-        return true;
-    }
-    return false;
-}
-
-bool agen_control_lbutton_handle(EKeystate s)
-{
-    switch (s)
-    {
-    case KEYSTATE_DOWN:
-        gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN);
-        break;
-    case KEYSTATE_UP:
-        gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP);
-        break;
-    default:
-        break;
-    }
-    return true;
-}
-
-#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);
-REGISTER_KEYBOARD_ACTION("push_forward", agent_push_forward);
-REGISTER_KEYBOARD_ACTION("push_backward", agent_push_backward);
-REGISTER_KEYBOARD_ACTION("look_up", agent_look_up);
-REGISTER_KEYBOARD_ACTION("look_down", agent_look_down);
-REGISTER_KEYBOARD_ACTION("toggle_fly", agent_toggle_fly);
-REGISTER_KEYBOARD_ACTION("turn_left", agent_turn_left);
-REGISTER_KEYBOARD_ACTION("turn_right", agent_turn_right);
-REGISTER_KEYBOARD_ACTION("slide_left", agent_slide_left);
-REGISTER_KEYBOARD_ACTION("slide_right", agent_slide_right);
-REGISTER_KEYBOARD_ACTION("spin_around_ccw", camera_spin_around_ccw);
-REGISTER_KEYBOARD_ACTION("spin_around_cw", camera_spin_around_cw);
-REGISTER_KEYBOARD_ACTION("spin_around_ccw_sitting", camera_spin_around_ccw_sitting);
-REGISTER_KEYBOARD_ACTION("spin_around_cw_sitting", camera_spin_around_cw_sitting);
-REGISTER_KEYBOARD_ACTION("spin_over", camera_spin_over);
-REGISTER_KEYBOARD_ACTION("spin_under", camera_spin_under);
-REGISTER_KEYBOARD_ACTION("spin_over_sitting", camera_spin_over_sitting);
-REGISTER_KEYBOARD_ACTION("spin_under_sitting", camera_spin_under_sitting);
-REGISTER_KEYBOARD_ACTION("move_forward", camera_move_forward);
-REGISTER_KEYBOARD_ACTION("move_backward", camera_move_backward);
-REGISTER_KEYBOARD_ACTION("move_forward_sitting", camera_move_forward_sitting);
-REGISTER_KEYBOARD_ACTION("move_backward_sitting", camera_move_backward_sitting);
-REGISTER_KEYBOARD_ACTION("pan_up", camera_pan_up);
-REGISTER_KEYBOARD_ACTION("pan_down", camera_pan_down);
-REGISTER_KEYBOARD_ACTION("pan_left", camera_pan_left);
-REGISTER_KEYBOARD_ACTION("pan_right", camera_pan_right);
-REGISTER_KEYBOARD_ACTION("pan_in", camera_pan_in);
-REGISTER_KEYBOARD_ACTION("pan_out", camera_pan_out);
-REGISTER_KEYBOARD_ACTION("move_forward_fast", camera_move_forward_fast);
-REGISTER_KEYBOARD_ACTION("move_backward_fast", camera_move_backward_fast);
-REGISTER_KEYBOARD_ACTION("edit_avatar_spin_ccw", edit_avatar_spin_ccw);
-REGISTER_KEYBOARD_ACTION("edit_avatar_spin_cw", edit_avatar_spin_cw);
-REGISTER_KEYBOARD_ACTION("edit_avatar_spin_over", edit_avatar_spin_over);
-REGISTER_KEYBOARD_ACTION("edit_avatar_spin_under", edit_avatar_spin_under);
-REGISTER_KEYBOARD_ACTION("edit_avatar_move_forward", edit_avatar_move_forward);
-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("run_forward", run_forward);
-REGISTER_KEYBOARD_ACTION("run_backward", run_backward);
-REGISTER_KEYBOARD_ACTION("run_left", run_left);
-REGISTER_KEYBOARD_ACTION("run_right", run_right);
-REGISTER_KEYBOARD_ACTION("toggle_run", toggle_run);
-REGISTER_KEYBOARD_ACTION("toggle_sit", toggle_sit);
-REGISTER_KEYBOARD_ACTION("toggle_pause_media", toggle_pause_media);
-REGISTER_KEYBOARD_ACTION("toggle_enable_media", toggle_enable_media);
-REGISTER_KEYBOARD_ACTION("teleport_to", teleport_to);
-REGISTER_KEYBOARD_ACTION("walk_to", walk_to);
-REGISTER_KEYBOARD_ACTION("toggle_voice", toggle_voice);
-REGISTER_KEYBOARD_ACTION("voice_follow_key", voice_follow_key);
-#undef REGISTER_KEYBOARD_ACTION
-
-LLViewerInput::LLViewerInput()
-{
-    resetBindings();
-
-	for (S32 i = 0; i < KEY_COUNT; i++)
-	{
-		mKeyHandledByUI[i] = FALSE;
-    }
-    for (S32 i = 0; i < CLICK_COUNT; i++)
-    {
-        mMouseLevel[i] = MOUSE_STATE_SILENT;
-    }
-	// we want the UI to never see these keys so that they can always control the avatar/camera
-	for(KEY k = KEY_PAD_UP; k <= KEY_PAD_DIVIDE; k++) 
-	{
-		mKeysSkippedByUI.insert(k);	
-	}
-}
-
-// static
-BOOL LLViewerInput::modeFromString(const std::string& string, S32 *mode)
-{
-	if (string == "FIRST_PERSON")
-	{
-		*mode = MODE_FIRST_PERSON;
-		return TRUE;
-	}
-	else if (string == "THIRD_PERSON")
-	{
-		*mode = MODE_THIRD_PERSON;
-		return TRUE;
-	}
-	else if (string == "EDIT_AVATAR")
-	{
-		*mode = MODE_EDIT_AVATAR;
-		return TRUE;
-	}
-	else if (string == "SITTING")
-	{
-		*mode = MODE_SITTING;
-		return TRUE;
-	}
-	else
-	{
-		*mode = MODE_THIRD_PERSON;
-		return FALSE;
-	}
-}
-
-// static
-BOOL LLViewerInput::mouseFromString(const std::string& string, EMouseClickType *mode)
-{
-    if (string == "LMB")
-    {
-        *mode = CLICK_LEFT;
-        return TRUE;
-    }
-    else if (string == "Double LMB")
-    {
-        *mode = CLICK_DOUBLELEFT;
-        return TRUE;
-    }
-    else if (string == "MMB")
-    {
-        *mode = CLICK_MIDDLE;
-        return TRUE;
-    }
-    else if (string == "MB4")
-    {
-        *mode = CLICK_BUTTON4;
-        return TRUE;
-    }
-    else if (string == "MB5")
-    {
-        *mode = CLICK_BUTTON5;
-        return TRUE;
-    }
-    else
-    {
-        *mode = CLICK_NONE;
-        return FALSE;
-    }
-}
-
-BOOL LLViewerInput::handleKey(KEY translated_key, MASK translated_mask, BOOL repeated)
-{
-	// check for re-map
-	EKeyboardMode mode = gViewerInput.getMode();
-	U32 keyidx = (translated_mask<<16) | translated_key;
-	key_remap_t::iterator iter = mRemapKeys[mode].find(keyidx);
-	if (iter != mRemapKeys[mode].end())
-	{
-		translated_key = (iter->second) & 0xff;
-		translated_mask = (iter->second)>>16;
-	}
-
-	// No repeats of F-keys
-	BOOL repeatable_key = (translated_key < KEY_F1 || translated_key > KEY_F12);
-	if (!repeatable_key && repeated)
-	{
-		return FALSE;
-	}
-
-	LL_DEBUGS("UserInput") << "keydown -" << translated_key << "-" << LL_ENDL;
-	// skip skipped keys
-	if(mKeysSkippedByUI.find(translated_key) != mKeysSkippedByUI.end()) 
-	{
-		mKeyHandledByUI[translated_key] = FALSE;
-		LL_INFOS("KeyboardHandling") << "Key wasn't handled by UI!" << LL_ENDL;
-	}
-	else
-	{
-		// it is sufficient to set this value once per call to handlekey
-		// without clearing it, as it is only used in the subsequent call to scanKey
-		mKeyHandledByUI[translated_key] = gViewerWindow->handleKey(translated_key, translated_mask); 
-		// mKeyHandledByUI is not what you think ... this indicates whether the UI has handled this keypress yet (any keypress)
-		// NOT whether some UI shortcut wishes to handle the keypress
-	  
-	}
-	return mKeyHandledByUI[translated_key];
-}
-
-BOOL LLViewerInput::handleKeyUp(KEY translated_key, MASK translated_mask)
-{
-	return gViewerWindow->handleKeyUp(translated_key, translated_mask);
-}
-
-BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name)
-{
-	S32 index;
-	typedef boost::function<bool(EKeystate)> function_t;
-	function_t function = NULL;
-	std::string name;
-
-	// Allow remapping of F2-F12
-	if (function_name[0] == 'F')
-	{
-		int c1 = function_name[1] - '0';
-		int c2 = function_name[2] ? function_name[2] - '0' : -1;
-		if (c1 >= 0 && c1 <= 9 && c2 >= -1 && c2 <= 9)
-		{
-			int idx = c1;
-			if (c2 >= 0)
-				idx = idx*10 + c2;
-			if (idx >=2 && idx <= 12)
-			{
-				U32 keyidx = ((mask<<16)|key);
-				(mRemapKeys[mode])[keyidx] = ((0<<16)|(KEY_F1+(idx-1)));
-				return TRUE;
-			}
-		}
-	}
-
-	// Not remapped, look for a function
-	
-	function_t* result = LLKeyboardActionRegistry::getValue(function_name);
-	if (result)
-	{
-		function = *result;
-	}
-
-	if (!function)
-	{
-		LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
-		return FALSE;
-	}
-
-	// check for duplicate first and overwrite
-    S32 size = mKeyBindings[mode].size();
-    for (index = 0; index < size; index++)
-    {
-        if (key == mKeyBindings[mode][index].mKey && mask == mKeyBindings[mode][index].mMask)
-            break;
-    }
-
-	if (mode >= MODE_COUNT)
-	{
-		LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
-		return FALSE;
-	}
-
-    LLKeyboardBinding bind;
-    bind.mKey = key;
-    bind.mMask = mask;
-    bind.mFunction = function;
-
-    mKeyBindings[mode].push_back(bind);
-
-	return TRUE;
-}
-
-BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const std::string& function_name)
-{
-    S32 index;
-    typedef boost::function<bool(EKeystate)> function_t;
-    function_t function = NULL;
-
-    function_t* result = LLKeyboardActionRegistry::getValue(function_name);
-    if (result)
-    {
-        function = *result;
-    }
-
-    if (!function)
-    {
-        LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
-        return FALSE;
-    }
-
-    // check for duplicate first and overwrite
-    S32 size = mMouseBindings[mode].size();
-    for (index = 0; index < size; index++)
-    {
-        if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask)
-            break;
-    }
-
-    if (mode >= MODE_COUNT)
-    {
-        LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
-        return FALSE;
-    }
-
-    LLMouseBinding bind;
-    bind.mMouse = mouse;
-    bind.mMask = mask;
-    bind.mFunction = function;
-
-    mMouseBindings[mode].push_back(bind);
-
-    return TRUE;
-}
-
-LLViewerInput::KeyBinding::KeyBinding()
-:	key("key"),
-	mouse("mouse"),
-	mask("mask"),
-	command("command")
-{}
-
-LLViewerInput::KeyMode::KeyMode()
-:	bindings("binding")
-{}
-
-LLViewerInput::Keys::Keys()
-:	first_person("first_person"),
-	third_person("third_person"),
-	sitting("sitting"),
-	edit_avatar("edit_avatar")
-{}
-
-void LLViewerInput::resetBindings()
-{
-    for (S32 i = 0; i < MODE_COUNT; i++)
-    {
-        mKeyBindings[i].clear();
-        mMouseBindings[i].clear();
-    }
-}
-
-S32 LLViewerInput::loadBindingsXML(const std::string& filename)
-{
-    resetBindings();
-
-	S32 binding_count = 0;
-	Keys keys;
-	LLSimpleXUIParser parser;
-
-	if (parser.readXUI(filename, keys) 
-		&& keys.validateBlock())
-	{
-		binding_count += loadBindingMode(keys.first_person, MODE_FIRST_PERSON);
-		binding_count += loadBindingMode(keys.third_person, MODE_THIRD_PERSON);
-		binding_count += loadBindingMode(keys.sitting, MODE_SITTING);
-		binding_count += loadBindingMode(keys.edit_avatar, MODE_EDIT_AVATAR);
-	}
-	return binding_count;
-}
-
-S32 count_masks(const MASK &mask)
-{
-    S32 res = 0;
-    if (mask & MASK_CONTROL)
-    {
-        res++;
-    }
-    if (mask & MASK_SHIFT)
-    {
-        res++;
-    }
-    if (mask & MASK_ALT)
-    {
-        res++;
-    }
-    return res;
-}
-
-bool compare_key_by_mask(LLKeyboardBinding i1, LLKeyboardBinding i2)
-{
-    return (count_masks(i1.mMask) > count_masks(i2.mMask));
-}
-
-bool compare_mouse_by_mask(LLMouseBinding i1, LLMouseBinding i2)
-{
-    return (count_masks(i1.mMask) > count_masks(i2.mMask));
-}
-
-S32 LLViewerInput::loadBindingMode(const LLViewerInput::KeyMode& keymode, S32 mode)
-{
-	S32 binding_count = 0;
-	for (LLInitParam::ParamIterator<KeyBinding>::const_iterator it = keymode.bindings.begin(), 
-			end_it = keymode.bindings.end();
-		it != end_it;
-		++it)
-	{
-        bool processed = false;
-        std::string key_str = it->key.getValue();
-        if (!key_str.empty() && key_str != "NONE")
-        {
-            KEY key;
-            LLKeyboard::keyFromString(key_str, &key);
-            if (key != KEY_NONE)
-            {
-                MASK mask;
-                LLKeyboard::maskFromString(it->mask, &mask);
-                bindKey(mode, key, mask, it->command);
-                processed = true;
-            }
-            else
-            {
-                LL_WARNS_ONCE() << "There might be issues in keybindings' file" << LL_ENDL;
-            }
-        }
-        if (!processed && it->mouse.isProvided() && !it->mouse.getValue().empty())
-        {
-            EMouseClickType mouse;
-            mouseFromString(it->mouse.getValue(), &mouse);
-            if (mouse != CLICK_NONE)
-            {
-                MASK mask;
-                LLKeyboard::maskFromString(it->mask, &mask);
-                bindMouse(mode, mouse, mask, it->command);
-                processed = true;
-            }
-            else
-            {
-                LL_WARNS_ONCE() << "There might be issues in keybindings' file" << LL_ENDL;
-            }
-        }
-        if (processed)
-        {
-            // total
-            binding_count++;
-        }
-    }
-
-    // sort lists by mask (so that Shift+W is executed before W, if both are assigned, but if Shift+W is not assigned W should be executed)
-    std::sort(mKeyBindings[mode].begin(), mKeyBindings[mode].end(), compare_key_by_mask);
-    std::sort(mMouseBindings[mode].begin(), mMouseBindings[mode].end(), compare_mouse_by_mask);
-
-	return binding_count;
-}
-
-EKeyboardMode LLViewerInput::getMode() const
-{
-	if ( gAgentCamera.cameraMouselook() )
-	{
-		return MODE_FIRST_PERSON;
-	}
-	else if ( gMorphView && gMorphView->getVisible())
-	{
-		return MODE_EDIT_AVATAR;
-	}
-	else if (isAgentAvatarValid() && gAgentAvatarp->isSitting())
-	{
-		return MODE_SITTING;
-	}
-	else
-	{
-		return MODE_THIRD_PERSON;
-	}
-}
-
-bool LLViewerInput::scanKey(const std::vector<LLKeyboardBinding> &binding,
-                               S32 binding_count,
-                               KEY key,
-                               MASK mask,
-                               BOOL key_down,
-                               BOOL key_up,
-                               BOOL key_level,
-                               bool repeat) const
-{
-	for (S32 i = 0; i < binding_count; i++)
-	{
-		if (binding[i].mKey == key)
-		{
-			if ((binding[i].mMask & mask) == binding[i].mMask)
-			{
-				bool res = false;
-				if (key_down && !repeat)
-				{
-					// ...key went down this frame, call function
-					res = binding[i].mFunction( KEYSTATE_DOWN );
-					return true;
-				}
-				else if (key_up)
-				{
-					// ...key went down this frame, call function
-					res = binding[i].mFunction( KEYSTATE_UP );
-				}
-				else if (key_level)
-				{
-					// ...key held down from previous frame
-					// Not windows, just call the function.
-					res = binding[i].mFunction( KEYSTATE_LEVEL );
-				}//if
-				// Key+Mask combinations are supposed to be unique, so we won't find anything else
-				return res;
-			}//if
-		}//if
-	}//for
-	return false;
-}
-
-// Called from scanKeyboard.
-bool LLViewerInput::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) const
-{
-	if (LLApp::isExiting())
-	{
-		return false;
-	}
-
-	S32 mode = getMode();
-	// Consider keyboard scanning as NOT mouse event. JC
-	MASK mask = gKeyboard->currentMask(FALSE);
-
-	if (mKeyHandledByUI[key])
-	{
-		return false;
-	}
-
-	// don't process key down on repeated keys
-	BOOL repeat = gKeyboard->getKeyRepeated(key);
-
-    bool res = scanKey(mKeyBindings[mode], mKeyBindings[mode].size(), key, mask, key_down, key_up, key_level, repeat);
-
-    if (!res && agent_control_lbutton.canHandle(CLICK_NONE, key, mask))
-    {
-        if (key_down && !repeat)
-        {
-            res = agen_control_lbutton_handle(KEYSTATE_DOWN);
-        }
-        if (key_up)
-        {
-            res = agen_control_lbutton_handle(KEYSTATE_UP);
-        }
-    }
-    return res;
-}
-
-BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down)
-{
-    BOOL handled = gViewerWindow->handleAnyMouseClick(window_impl, pos, mask, clicktype, down);
-
-    if (clicktype != CLICK_NONE)
-    {
-        // Special case
-        // If UI doesn't handle double click, LMB click is issued, so supres LMB 'down' when doubleclick is set
-        // handle !down as if we are handling doubleclick
-
-        bool double_click_sp = (clicktype == CLICK_LEFT
-            && (mMouseLevel[CLICK_DOUBLELEFT] != MOUSE_STATE_SILENT)
-            && mMouseLevel[CLICK_LEFT] == MOUSE_STATE_SILENT);
-        if (double_click_sp && !down)
-        {
-            // Process doubleclick instead
-            clicktype = CLICK_DOUBLELEFT;
-        }
-
-
-        if (double_click_sp && down)
-        {
-            // Consume click.
-            // Due to handling, double click that is not handled will be immediately followed by LMB click
-        }
-        // If UI handled 'down', it should handle 'up' as well
-        // If we handle 'down' not by UI, then we should handle 'up'/'level' regardless of UI
-        else if (handled)
-        {
-            // UI handled new 'down' so iterupt whatever state we were in.
-            if (mMouseLevel[clicktype] != MOUSE_STATE_SILENT)
-            {
-                if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN)
-                {
-                    mMouseLevel[clicktype] = MOUSE_STATE_CLICK;
-                }
-                else
-                {
-                    mMouseLevel[clicktype] = MOUSE_STATE_UP;
-                }
-            }
-        }
-        else if (down)
-        {
-            if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN)
-            {
-                // this is repeated hit (mouse does not repeat event until release)
-                // for now treat rapid clicking like mouse being held
-                mMouseLevel[clicktype] = MOUSE_STATE_LEVEL;
-            }
-            else
-            {
-                mMouseLevel[clicktype] = MOUSE_STATE_DOWN;
-            }
-        }
-        else if (mMouseLevel[clicktype] != MOUSE_STATE_SILENT)
-        {
-            // Released mouse key
-            if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN)
-            {
-                mMouseLevel[clicktype] = MOUSE_STATE_CLICK;
-            }
-            else 
-            {
-                mMouseLevel[clicktype] = MOUSE_STATE_UP;
-            }
-        }
-    }
-
-    return handled;
-}
-
-bool LLViewerInput::scanMouse(const std::vector<LLMouseBinding> &binding, S32 binding_count, EMouseClickType mouse, MASK mask, EMouseState state) const
-{
-    for (S32 i = 0; i < binding_count; i++)
-    {
-        if (binding[i].mMouse == mouse && (binding[i].mMask & mask) == binding[i].mMask)
-        {
-            bool res = false;
-            switch (state)
-            {
-            case MOUSE_STATE_DOWN:
-                res = binding[i].mFunction(KEYSTATE_DOWN);
-                break;
-            case MOUSE_STATE_CLICK:
-                // Button went down and up in scope of single frame
-                // might not work best with some functions,
-                // but some function need specific states specifically
-                res = binding[i].mFunction(KEYSTATE_DOWN);
-                res |= binding[i].mFunction(KEYSTATE_UP);
-                break;
-            case MOUSE_STATE_LEVEL:
-                res = binding[i].mFunction(KEYSTATE_LEVEL);
-                break;
-            case MOUSE_STATE_UP:
-                res = binding[i].mFunction(KEYSTATE_UP);
-                break;
-            default:
-                break;
-            }
-            // Key+Mask combinations are supposed to be unique, no need to continue
-            return res;
-        }
-    }
-    return false;
-}
-
-// todo: this recods key, scanMouse() triggers functions with EKeystate
-bool LLViewerInput::scanMouse(EMouseClickType click, EMouseState state) const
-{
-    bool res = false;
-    S32 mode = getMode();
-    MASK mask = gKeyboard->currentMask(TRUE);
-    res = scanMouse(mMouseBindings[mode], mMouseBindings[mode].size(), click, mask, state);
-    // no user defined actions found or those actions can't handle the key/button, handle control if nessesary
-    if (!res && agent_control_lbutton.canHandle(click, KEY_NONE, mask))
-    {
-        switch (state)
-        {
-        case MOUSE_STATE_DOWN:
-            agen_control_lbutton_handle(KEYSTATE_DOWN);
-            res = true;
-            break;
-        case MOUSE_STATE_CLICK:
-            // might not work best with some functions,
-            // but some function need specific states too specifically
-            agen_control_lbutton_handle(KEYSTATE_DOWN);
-            agen_control_lbutton_handle(KEYSTATE_UP);
-            res = true;
-            break;
-        case MOUSE_STATE_UP:
-            agen_control_lbutton_handle(KEYSTATE_UP);
-            res = true;
-            break;
-        default:
-            break;
-        }
-    }
-    return res;
-}
-
-void LLViewerInput::scanMouse()
-{
-    for (S32 i = 0; i < CLICK_COUNT; i++)
-    {
-        if (mMouseLevel[i] != MOUSE_STATE_SILENT)
-        {
-            scanMouse((EMouseClickType)i, mMouseLevel[i]);
-            if (mMouseLevel[i] == MOUSE_STATE_DOWN)
-            {
-                // mouse doesn't support 'continued' state, so after handling, switch to LEVEL
-                mMouseLevel[i] = MOUSE_STATE_LEVEL;
-            }
-            else if (mMouseLevel[i] == MOUSE_STATE_UP || mMouseLevel[i] == MOUSE_STATE_CLICK)
-            {
-                mMouseLevel[i] = MOUSE_STATE_SILENT;
-            }
-        }
-    }
-}
diff --git a/indra/newview/llviewerinput.h b/indra/newview/llviewerinput.h
deleted file mode 100644
index 1fe55bd585..0000000000
--- a/indra/newview/llviewerinput.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/** 
- * @file llviewerinput.h
- * @brief LLViewerInput class header file
- *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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_LLVIEWERINPUT_H
-#define LL_LLVIEWERINPUT_H
-
-#include "llkeyboard.h" // For EKeystate
-#include "llinitparam.h"
-
-const S32 MAX_KEY_BINDINGS = 128; // was 60
-
-class LLNamedFunction
-{
-public:
-	LLNamedFunction() : mFunction(NULL) { };
-	~LLNamedFunction() { };
-
-	std::string	mName;
-	LLKeyFunc	mFunction;
-};
-
-class LLKeyboardBinding
-{
-public:
-    KEY				mKey;
-    MASK			mMask;
-
-    LLKeyFunc		mFunction;
-};
-
-class LLMouseBinding
-{
-public:
-    EMouseClickType	mMouse;
-    MASK			mMask;
-
-    LLKeyFunc		mFunction;
-};
-
-
-typedef enum e_keyboard_mode
-{
-	MODE_FIRST_PERSON,
-	MODE_THIRD_PERSON,
-	MODE_EDIT_AVATAR,
-	MODE_SITTING,
-	MODE_COUNT
-} EKeyboardMode;
-
-class LLWindow;
-
-void bind_keyboard_functions();
-
-class LLViewerInput
-{
-public:
-	struct KeyBinding : public LLInitParam::Block<KeyBinding>
-	{
-		Mandatory<std::string>	key,
-								mask,
-								command;
-		Optional<std::string>	mouse; // Note, not mandatory for the sake of backward campatibility with keys.xml
-
-		KeyBinding();
-	};
-
-	struct KeyMode : public LLInitParam::Block<KeyMode>
-	{
-		Multiple<KeyBinding>		bindings;
-
-		KeyMode();
-	};
-
-	struct Keys : public LLInitParam::Block<Keys>
-	{
-		Optional<KeyMode>	first_person,
-							third_person,
-							sitting,
-							edit_avatar;
-
-		Keys();
-	};
-
-	LLViewerInput();
-
-	BOOL			handleKey(KEY key, MASK mask, BOOL repeated);
-	BOOL			handleKeyUp(KEY key, MASK mask);
-
-	S32				loadBindingsXML(const std::string& filename);										// returns number bound, 0 on error
-	EKeyboardMode	getMode() const;
-
-	static BOOL		modeFromString(const std::string& string, S32 *mode);			// False on failure
-	static BOOL		mouseFromString(const std::string& string, EMouseClickType *mode);// False on failure
-
-    bool            scanKey(KEY key,
-                            BOOL key_down,
-                            BOOL key_up,
-                            BOOL key_level) const;
-
-    // handleMouse() records state, scanMouse() goes through states, scanMouse(click) processes individual saved states after UI is done with them
-    BOOL            handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down);
-    void            scanMouse();
-
-private:
-    bool            scanKey(const std::vector<LLKeyboardBinding> &binding,
-                            S32 binding_count,
-                            KEY key,
-                            MASK mask,
-                            BOOL key_down,
-                            BOOL key_up,
-                            BOOL key_level,
-                            bool repeat) const;
-
-    enum EMouseState
-    {
-        MOUSE_STATE_DOWN, // key down this frame
-        MOUSE_STATE_CLICK, // key went up and down in scope of same frame
-        MOUSE_STATE_LEVEL, // clicked again fast, or never released
-        MOUSE_STATE_UP, // went up this frame
-        MOUSE_STATE_SILENT // notified about 'up', do not notify again
-    };
-    bool			scanMouse(EMouseClickType click, EMouseState state) const;
-    bool            scanMouse(const std::vector<LLMouseBinding> &binding,
-                          S32 binding_count,
-                          EMouseClickType mouse,
-                          MASK mask,
-                          EMouseState state) const;
-
-    S32				loadBindingMode(const LLViewerInput::KeyMode& keymode, S32 mode);
-    BOOL			bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name);
-    BOOL			bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const std::string& function_name);
-    void			resetBindings();
-
-	// Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here
-
-    // TODO: at some point it is better to remake this, especially keyaboard part
-    // would be much better to send to functions actual state of the button than
-    // to send what we think function wants based on collection of bools (mKeyRepeated, mKeyLevel, mKeyDown)
-    std::vector<LLKeyboardBinding>	mKeyBindings[MODE_COUNT];
-    std::vector<LLMouseBinding>		mMouseBindings[MODE_COUNT];
-
-	typedef std::map<U32, U32> key_remap_t;
-	key_remap_t		mRemapKeys[MODE_COUNT];
-	std::set<KEY>	mKeysSkippedByUI;
-	BOOL			mKeyHandledByUI[KEY_COUNT];		// key processed successfully by UI
-
-    // This is indentical to what llkeyboard does (mKeyRepeated, mKeyLevel, mKeyDown e t c),
-    // just instead of remembering individually as bools,  we record state as enum
-    EMouseState		mMouseLevel[CLICK_COUNT];	// records of key state
-};
-
-extern LLViewerInput gViewerInput;
-
-#endif // LL_LLVIEWERINPUT_H
diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp
new file mode 100644
index 0000000000..6914e0fc2b
--- /dev/null
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -0,0 +1,1039 @@
+/** 
+ * @file llviewerkeyboard.cpp
+ * @brief LLViewerKeyboard class implementation
+ *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llappviewer.h"
+#include "llfloaterreg.h"
+#include "llviewerkeyboard.h"
+#include "llmath.h"
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llfloaterimnearbychat.h"
+#include "llviewercontrol.h"
+#include "llfocusmgr.h"
+#include "llmorphview.h"
+#include "llmoveview.h"
+#include "lltoolfocus.h"
+#include "llviewerwindow.h"
+#include "llvoavatarself.h"
+#include "llfloatercamera.h"
+#include "llinitparam.h"
+
+//
+// Constants
+//
+
+const F32 FLY_TIME = 0.5f;
+const F32 FLY_FRAMES = 4;
+
+const F32 NUDGE_TIME = 0.25f;  // in seconds
+const S32 NUDGE_FRAMES = 2;
+const F32 ORBIT_NUDGE_RATE = 0.05f;  // fraction of normal speed
+
+struct LLKeyboardActionRegistry 
+:	public LLRegistrySingleton<std::string, boost::function<void (EKeystate keystate)>, LLKeyboardActionRegistry>
+{
+	LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry);
+};
+
+LLViewerKeyboard gViewerKeyboard;
+
+void agent_jump( EKeystate s )
+{
+	static BOOL first_fly_attempt(TRUE);
+	if (KEYSTATE_UP == s)
+	{
+		first_fly_attempt = TRUE;
+		return;
+	}
+	F32 time = gKeyboard->getCurKeyElapsedTime();
+	S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
+
+	if( time < FLY_TIME 
+		|| frame_count <= FLY_FRAMES 
+		|| gAgent.upGrabbed()
+		|| !gSavedSettings.getBOOL("AutomaticFly"))
+	{
+		gAgent.moveUp(1);
+	}
+	else
+	{
+		gAgent.setFlying(TRUE, first_fly_attempt);
+		first_fly_attempt = FALSE;
+		gAgent.moveUp(1);
+	}
+}
+
+void agent_push_down( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gAgent.moveUp(-1);
+}
+
+static void agent_check_temporary_run(LLAgent::EDoubleTapRunMode mode)
+{
+	if (gAgent.mDoubleTapRunMode == mode &&
+		gAgent.getRunning() &&
+		!gAgent.getAlwaysRun())
+	{
+		// Turn off temporary running.
+		gAgent.clearRunning();
+		gAgent.sendWalkRun(gAgent.getRunning());
+	}
+}
+
+static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode mode)
+{
+	if (KEYSTATE_UP == s)
+	{
+		// Note: in case shift is already released, slide left/right run
+		// will be released in agent_turn_left()/agent_turn_right()
+		agent_check_temporary_run(mode);
+	}
+	else if (gSavedSettings.getBOOL("AllowTapTapHoldRun") &&
+		 KEYSTATE_DOWN == s &&
+		 !gAgent.getRunning())
+	{
+		if (gAgent.mDoubleTapRunMode == mode &&
+		    gAgent.mDoubleTapRunTimer.getElapsedTimeF32() < NUDGE_TIME)
+		{
+			// Same walk-key was pushed again quickly; this is a
+			// double-tap so engage temporary running.
+			gAgent.setRunning();
+			gAgent.sendWalkRun(gAgent.getRunning());
+		}
+
+		// Pressing any walk-key resets the double-tap timer
+		gAgent.mDoubleTapRunTimer.reset();
+		gAgent.mDoubleTapRunMode = mode;
+	}
+}
+
+static void agent_push_forwardbackward( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode )
+{
+	agent_handle_doubletap_run(s, mode);
+	if (KEYSTATE_UP == s) return;
+
+	F32 time = gKeyboard->getCurKeyElapsedTime();
+	S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
+
+	if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES)
+	{
+		gAgent.moveAtNudge(direction);
+	}
+	else
+	{
+		gAgent.moveAt(direction);
+	}
+}
+
+void camera_move_forward( EKeystate s );
+
+void agent_push_forward( EKeystate s )
+{
+	if(gAgent.isMovementLocked()) return;
+
+	//in free camera control mode we need to intercept keyboard events for avatar movements
+	if (LLFloaterCamera::inFreeCameraMode())
+	{
+		camera_move_forward(s);
+	}
+	else
+	{
+		agent_push_forwardbackward(s, 1, LLAgent::DOUBLETAP_FORWARD);
+	}
+}
+
+void camera_move_backward( EKeystate s );
+
+void agent_push_backward( EKeystate s )
+{
+	if(gAgent.isMovementLocked()) return;
+
+	//in free camera control mode we need to intercept keyboard events for avatar movements
+	if (LLFloaterCamera::inFreeCameraMode())
+	{
+		camera_move_backward(s);
+	}
+	else if (!gAgent.backwardGrabbed() && gAgentAvatarp->isSitting() && gSavedSettings.getBOOL("LeaveMouselook"))
+	{
+		gAgentCamera.changeCameraToThirdPerson();
+	}
+	else
+	{
+		agent_push_forwardbackward(s, -1, LLAgent::DOUBLETAP_BACKWARD);
+	}
+}
+
+static void agent_slide_leftright( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode )
+{
+	agent_handle_doubletap_run(s, mode);
+	if( KEYSTATE_UP == s ) return;
+	F32 time = gKeyboard->getCurKeyElapsedTime();
+	S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
+
+	if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES)
+	{
+		gAgent.moveLeftNudge(direction);
+	}
+	else
+	{
+		gAgent.moveLeft(direction);
+	}
+}
+
+
+void agent_slide_left( EKeystate s )
+{
+	if(gAgent.isMovementLocked()) return;
+	agent_slide_leftright(s, 1, LLAgent::DOUBLETAP_SLIDELEFT);
+}
+
+
+void agent_slide_right( EKeystate s )
+{
+	if(gAgent.isMovementLocked()) return;
+	agent_slide_leftright(s, -1, LLAgent::DOUBLETAP_SLIDERIGHT);
+}
+
+void camera_spin_around_cw( EKeystate s );
+
+void agent_turn_left( EKeystate s )
+{
+	//in free camera control mode we need to intercept keyboard events for avatar movements
+	if (LLFloaterCamera::inFreeCameraMode())
+	{
+		camera_spin_around_cw(s);
+		return;
+	}
+
+	if(gAgent.isMovementLocked()) return;
+
+	if (LLToolCamera::getInstance()->mouseSteerMode())
+	{
+		agent_slide_left(s);
+	}
+	else
+	{
+		if (KEYSTATE_UP == s)
+		{
+			// Check temporary running. In case user released 'left' key with shift already released.
+			agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDELEFT);
+			return;
+		}
+		F32 time = gKeyboard->getCurKeyElapsedTime();
+		gAgent.moveYaw( LLFloaterMove::getYawRate( time ) );
+	}
+}
+
+void camera_spin_around_ccw( EKeystate s );
+
+void agent_turn_right( EKeystate s )
+{
+	//in free camera control mode we need to intercept keyboard events for avatar movements
+	if (LLFloaterCamera::inFreeCameraMode())
+	{
+		camera_spin_around_ccw(s);
+		return;
+	}
+
+	if(gAgent.isMovementLocked()) return;
+
+	if (LLToolCamera::getInstance()->mouseSteerMode())
+	{
+		agent_slide_right(s);
+	}
+	else
+	{
+		if (KEYSTATE_UP == s)
+		{
+			// Check temporary running. In case user released 'right' key with shift already released.
+			agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDERIGHT);
+			return;
+		}
+		F32 time = gKeyboard->getCurKeyElapsedTime();
+		gAgent.moveYaw( -LLFloaterMove::getYawRate( time ) );
+	}
+}
+
+void agent_look_up( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gAgent.movePitch(-1);
+	//gAgent.rotate(-2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
+}
+
+
+void agent_look_down( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gAgent.movePitch(1);
+	//gAgent.rotate(2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
+}
+
+void agent_toggle_fly( EKeystate s )
+{
+	// Only catch the edge
+	if (KEYSTATE_DOWN == s )
+	{
+		LLAgent::toggleFlying();
+	}
+}
+
+F32 get_orbit_rate()
+{
+	F32 time = gKeyboard->getCurKeyElapsedTime();
+	if( time < NUDGE_TIME )
+	{
+		F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME;
+		//LL_INFOS() << rate << LL_ENDL;
+		return rate;
+	}
+	else
+	{
+		return 1;
+	}
+}
+
+void camera_spin_around_ccw( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gAgentCamera.unlockView();
+	gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
+}
+
+
+void camera_spin_around_cw( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gAgentCamera.unlockView();
+	gAgentCamera.setOrbitRightKey( get_orbit_rate() );
+}
+
+void camera_spin_around_ccw_sitting( EKeystate s )
+{
+	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT ) return;
+	if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning())
+	{
+		//send keystrokes, but do not change camera
+		agent_turn_right(s);
+	}
+	else
+	{
+		//change camera but do not send keystrokes
+		gAgentCamera.unlockView();
+		gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
+	}
+}
+
+
+void camera_spin_around_cw_sitting( EKeystate s )
+{
+	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT ) return;
+	if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning())
+	{
+		//send keystrokes, but do not change camera
+		agent_turn_left(s);
+	}
+	else
+	{
+		//change camera but do not send keystrokes
+		gAgentCamera.unlockView();
+		gAgentCamera.setOrbitRightKey( get_orbit_rate() );
+	}
+}
+
+
+void camera_spin_over( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gAgentCamera.unlockView();
+	gAgentCamera.setOrbitUpKey( get_orbit_rate() );
+}
+
+
+void camera_spin_under( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gAgentCamera.unlockView();
+	gAgentCamera.setOrbitDownKey( get_orbit_rate() );
+}
+
+void camera_spin_over_sitting( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	if (gAgent.upGrabbed() || gAgentCamera.sitCameraEnabled())
+	{
+		//send keystrokes, but do not change camera
+		agent_jump(s);
+	}
+	else
+	{
+		//change camera but do not send keystrokes
+		gAgentCamera.setOrbitUpKey( get_orbit_rate() );
+	}
+}
+
+
+void camera_spin_under_sitting( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	if (gAgent.downGrabbed() || gAgentCamera.sitCameraEnabled())
+	{
+		//send keystrokes, but do not change camera
+		agent_push_down(s);
+	}
+	else
+	{
+		//change camera but do not send keystrokes
+		gAgentCamera.setOrbitDownKey( get_orbit_rate() );
+	}
+}
+
+void camera_move_forward( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gAgentCamera.unlockView();
+	gAgentCamera.setOrbitInKey( get_orbit_rate() );
+}
+
+
+void camera_move_backward( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gAgentCamera.unlockView();
+	gAgentCamera.setOrbitOutKey( get_orbit_rate() );
+}
+
+void camera_move_forward_sitting( EKeystate s )
+{
+	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD ) return;
+	if (gAgent.forwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun()))
+	{
+		agent_push_forward(s);
+	}
+	else
+	{
+		gAgentCamera.setOrbitInKey( get_orbit_rate() );
+	}
+}
+
+
+void camera_move_backward_sitting( EKeystate s )
+{
+	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD ) return;
+
+	if (gAgent.backwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun()))
+	{
+		agent_push_backward(s);
+	}
+	else
+	{
+		gAgentCamera.setOrbitOutKey( get_orbit_rate() );
+	}
+}
+
+void camera_pan_up( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gAgentCamera.unlockView();
+	gAgentCamera.setPanUpKey( get_orbit_rate() );
+}
+
+void camera_pan_down( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gAgentCamera.unlockView();
+	gAgentCamera.setPanDownKey( get_orbit_rate() );
+}
+
+void camera_pan_left( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gAgentCamera.unlockView();
+	gAgentCamera.setPanLeftKey( get_orbit_rate() );
+}
+
+void camera_pan_right( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gAgentCamera.unlockView();
+	gAgentCamera.setPanRightKey( get_orbit_rate() );
+}
+
+void camera_pan_in( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gAgentCamera.unlockView();
+	gAgentCamera.setPanInKey( get_orbit_rate() );
+}
+
+void camera_pan_out( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gAgentCamera.unlockView();
+	gAgentCamera.setPanOutKey( get_orbit_rate() );
+}
+
+void camera_move_forward_fast( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gAgentCamera.unlockView();
+	gAgentCamera.setOrbitInKey(2.5f);
+}
+
+void camera_move_backward_fast( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gAgentCamera.unlockView();
+	gAgentCamera.setOrbitOutKey(2.5f);
+}
+
+
+void edit_avatar_spin_ccw( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gMorphView->setCameraDrivenByKeys( TRUE );
+	gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
+	//gMorphView->orbitLeft( get_orbit_rate() );
+}
+
+
+void edit_avatar_spin_cw( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gMorphView->setCameraDrivenByKeys( TRUE );
+	gAgentCamera.setOrbitRightKey( get_orbit_rate() );
+	//gMorphView->orbitRight( get_orbit_rate() );
+}
+
+void edit_avatar_spin_over( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gMorphView->setCameraDrivenByKeys( TRUE );
+	gAgentCamera.setOrbitUpKey( get_orbit_rate() );
+	//gMorphView->orbitUp( get_orbit_rate() );
+}
+
+
+void edit_avatar_spin_under( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gMorphView->setCameraDrivenByKeys( TRUE );
+	gAgentCamera.setOrbitDownKey( get_orbit_rate() );
+	//gMorphView->orbitDown( get_orbit_rate() );
+}
+
+void edit_avatar_move_forward( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gMorphView->setCameraDrivenByKeys( TRUE );
+	gAgentCamera.setOrbitInKey( get_orbit_rate() );
+	//gMorphView->orbitIn();
+}
+
+
+void edit_avatar_move_backward( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	gMorphView->setCameraDrivenByKeys( TRUE );
+	gAgentCamera.setOrbitOutKey( get_orbit_rate() );
+	//gMorphView->orbitOut();
+}
+
+void stop_moving( EKeystate s )
+{
+	if( KEYSTATE_UP == s  ) return;
+	// stop agent
+	gAgent.setControlFlags(AGENT_CONTROL_STOP);
+
+	// cancel autopilot
+	gAgent.stopAutoPilot();
+}
+
+void start_chat( EKeystate s )
+{
+    if (LLAppViewer::instance()->quitRequested())
+    {
+        return; // can't talk, gotta go, kthxbye!
+    }
+    
+	// start chat
+	LLFloaterIMNearbyChat::startChat(NULL);
+}
+
+void start_gesture( EKeystate s )
+{
+	LLUICtrl* focus_ctrlp = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
+	if (KEYSTATE_UP == s &&
+		! (focus_ctrlp && focus_ctrlp->acceptsTextInput()))
+	{
+ 		if ((LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"))->getCurrentChat().empty())
+ 		{
+ 			// No existing chat in chat editor, insert '/'
+ 			LLFloaterIMNearbyChat::startChat("/");
+ 		}
+ 		else
+ 		{
+ 			// Don't overwrite existing text in chat editor
+ 			LLFloaterIMNearbyChat::startChat(NULL);
+ 		}
+	}
+}
+
+#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);
+REGISTER_KEYBOARD_ACTION("push_forward", agent_push_forward);
+REGISTER_KEYBOARD_ACTION("push_backward", agent_push_backward);
+REGISTER_KEYBOARD_ACTION("look_up", agent_look_up);
+REGISTER_KEYBOARD_ACTION("look_down", agent_look_down);
+REGISTER_KEYBOARD_ACTION("toggle_fly", agent_toggle_fly);
+REGISTER_KEYBOARD_ACTION("turn_left", agent_turn_left);
+REGISTER_KEYBOARD_ACTION("turn_right", agent_turn_right);
+REGISTER_KEYBOARD_ACTION("slide_left", agent_slide_left);
+REGISTER_KEYBOARD_ACTION("slide_right", agent_slide_right);
+REGISTER_KEYBOARD_ACTION("spin_around_ccw", camera_spin_around_ccw);
+REGISTER_KEYBOARD_ACTION("spin_around_cw", camera_spin_around_cw);
+REGISTER_KEYBOARD_ACTION("spin_around_ccw_sitting", camera_spin_around_ccw_sitting);
+REGISTER_KEYBOARD_ACTION("spin_around_cw_sitting", camera_spin_around_cw_sitting);
+REGISTER_KEYBOARD_ACTION("spin_over", camera_spin_over);
+REGISTER_KEYBOARD_ACTION("spin_under", camera_spin_under);
+REGISTER_KEYBOARD_ACTION("spin_over_sitting", camera_spin_over_sitting);
+REGISTER_KEYBOARD_ACTION("spin_under_sitting", camera_spin_under_sitting);
+REGISTER_KEYBOARD_ACTION("move_forward", camera_move_forward);
+REGISTER_KEYBOARD_ACTION("move_backward", camera_move_backward);
+REGISTER_KEYBOARD_ACTION("move_forward_sitting", camera_move_forward_sitting);
+REGISTER_KEYBOARD_ACTION("move_backward_sitting", camera_move_backward_sitting);
+REGISTER_KEYBOARD_ACTION("pan_up", camera_pan_up);
+REGISTER_KEYBOARD_ACTION("pan_down", camera_pan_down);
+REGISTER_KEYBOARD_ACTION("pan_left", camera_pan_left);
+REGISTER_KEYBOARD_ACTION("pan_right", camera_pan_right);
+REGISTER_KEYBOARD_ACTION("pan_in", camera_pan_in);
+REGISTER_KEYBOARD_ACTION("pan_out", camera_pan_out);
+REGISTER_KEYBOARD_ACTION("move_forward_fast", camera_move_forward_fast);
+REGISTER_KEYBOARD_ACTION("move_backward_fast", camera_move_backward_fast);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_ccw", edit_avatar_spin_ccw);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_cw", edit_avatar_spin_cw);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_over", edit_avatar_spin_over);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_under", edit_avatar_spin_under);
+REGISTER_KEYBOARD_ACTION("edit_avatar_move_forward", edit_avatar_move_forward);
+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);
+#undef REGISTER_KEYBOARD_ACTION
+
+LLViewerKeyboard::LLViewerKeyboard()
+{
+	for (S32 i = 0; i < MODE_COUNT; i++)
+	{
+		mBindingCount[i] = 0;
+	}
+
+	for (S32 i = 0; i < KEY_COUNT; i++)
+	{
+		mKeyHandledByUI[i] = FALSE;
+	}
+	// we want the UI to never see these keys so that they can always control the avatar/camera
+	for(KEY k = KEY_PAD_UP; k <= KEY_PAD_DIVIDE; k++) 
+	{
+		mKeysSkippedByUI.insert(k);	
+	}
+}
+
+BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode)
+{
+	if (string == "FIRST_PERSON")
+	{
+		*mode = MODE_FIRST_PERSON;
+		return TRUE;
+	}
+	else if (string == "THIRD_PERSON")
+	{
+		*mode = MODE_THIRD_PERSON;
+		return TRUE;
+	}
+	else if (string == "EDIT")
+	{
+		*mode = MODE_EDIT;
+		return TRUE;
+	}
+	else if (string == "EDIT_AVATAR")
+	{
+		*mode = MODE_EDIT_AVATAR;
+		return TRUE;
+	}
+	else if (string == "SITTING")
+	{
+		*mode = MODE_SITTING;
+		return TRUE;
+	}
+	else
+	{
+		*mode = MODE_THIRD_PERSON;
+		return FALSE;
+	}
+}
+
+BOOL LLViewerKeyboard::handleKey(KEY translated_key,  MASK translated_mask, BOOL repeated)
+{
+	// check for re-map
+	EKeyboardMode mode = gViewerKeyboard.getMode();
+	U32 keyidx = (translated_mask<<16) | translated_key;
+	key_remap_t::iterator iter = mRemapKeys[mode].find(keyidx);
+	if (iter != mRemapKeys[mode].end())
+	{
+		translated_key = (iter->second) & 0xff;
+		translated_mask = (iter->second)>>16;
+	}
+
+	// No repeats of F-keys
+	BOOL repeatable_key = (translated_key < KEY_F1 || translated_key > KEY_F12);
+	if (!repeatable_key && repeated)
+	{
+		return FALSE;
+	}
+
+	LL_DEBUGS("UserInput") << "keydown -" << translated_key << "-" << LL_ENDL;
+	// skip skipped keys
+	if(mKeysSkippedByUI.find(translated_key) != mKeysSkippedByUI.end()) 
+	{
+		mKeyHandledByUI[translated_key] = FALSE;
+		LL_INFOS("KeyboardHandling") << "Key wasn't handled by UI!" << LL_ENDL;
+	}
+	else
+	{
+		// it is sufficient to set this value once per call to handlekey
+		// without clearing it, as it is only used in the subsequent call to scanKey
+		mKeyHandledByUI[translated_key] = gViewerWindow->handleKey(translated_key, translated_mask); 
+		// mKeyHandledByUI is not what you think ... this indicates whether the UI has handled this keypress yet (any keypress)
+		// NOT whether some UI shortcut wishes to handle the keypress
+	  
+	}
+	return mKeyHandledByUI[translated_key];
+}
+
+BOOL LLViewerKeyboard::handleKeyUp(KEY translated_key, MASK translated_mask)
+{
+	return gViewerWindow->handleKeyUp(translated_key, translated_mask);
+}
+
+BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name)
+{
+	S32 index;
+	typedef boost::function<void(EKeystate)> function_t;
+	function_t function = NULL;
+	std::string name;
+
+	// Allow remapping of F2-F12
+	if (function_name[0] == 'F')
+	{
+		int c1 = function_name[1] - '0';
+		int c2 = function_name[2] ? function_name[2] - '0' : -1;
+		if (c1 >= 0 && c1 <= 9 && c2 >= -1 && c2 <= 9)
+		{
+			int idx = c1;
+			if (c2 >= 0)
+				idx = idx*10 + c2;
+			if (idx >=2 && idx <= 12)
+			{
+				U32 keyidx = ((mask<<16)|key);
+				(mRemapKeys[mode])[keyidx] = ((0<<16)|(KEY_F1+(idx-1)));
+				return TRUE;
+			}
+		}
+	}
+
+	// Not remapped, look for a function
+	
+	function_t* result = LLKeyboardActionRegistry::getValue(function_name);
+	if (result)
+	{
+		function = *result;
+	}
+
+	if (!function)
+	{
+		LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
+		return FALSE;
+	}
+
+	// check for duplicate first and overwrite
+	for (index = 0; index < mBindingCount[mode]; index++)
+	{
+		if (key == mBindings[mode][index].mKey && mask == mBindings[mode][index].mMask)
+			break;
+	}
+
+	if (index >= MAX_KEY_BINDINGS)
+	{
+		LL_ERRS() << "LLKeyboard::bindKey() - too many keys for mode " << mode << LL_ENDL;
+		return FALSE;
+	}
+
+	if (mode >= MODE_COUNT)
+	{
+		LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
+		return FALSE;
+	}
+
+	mBindings[mode][index].mKey = key;
+	mBindings[mode][index].mMask = mask;
+	mBindings[mode][index].mFunction = function;
+
+	if (index == mBindingCount[mode])
+		mBindingCount[mode]++;
+
+	return TRUE;
+}
+
+LLViewerKeyboard::KeyBinding::KeyBinding()
+:	key("key"),
+	mask("mask"),
+	command("command")
+{}
+
+LLViewerKeyboard::KeyMode::KeyMode(EKeyboardMode _mode)
+:	bindings("binding"),
+	mode(_mode)
+{}
+
+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))
+{}
+
+S32 LLViewerKeyboard::loadBindingsXML(const std::string& filename)
+{
+	S32 binding_count = 0;
+	Keys keys;
+	LLSimpleXUIParser parser;
+
+	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);
+	}
+	return binding_count;
+}
+
+S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode)
+{
+	S32 binding_count = 0;
+	for (LLInitParam::ParamIterator<KeyBinding>::const_iterator it = keymode.bindings.begin(), 
+			end_it = keymode.bindings.end();
+		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++;
+	}
+
+	return binding_count;
+}
+
+S32 LLViewerKeyboard::loadBindings(const std::string& filename)
+{
+	LLFILE *fp;
+	const S32 BUFFER_SIZE = 2048;
+	char buffer[BUFFER_SIZE];	/* Flawfinder: ignore */
+	// *NOTE: This buffer size is hard coded into scanf() below.
+	char mode_string[MAX_STRING] = "";	/* Flawfinder: ignore */
+	char key_string[MAX_STRING] = "";	/* Flawfinder: ignore */
+	char mask_string[MAX_STRING] = "";	/* Flawfinder: ignore */
+	char function_string[MAX_STRING] = "";	/* Flawfinder: ignore */
+	S32 mode = MODE_THIRD_PERSON;
+	KEY key = 0;
+	MASK mask = 0;
+	S32 tokens_read;
+	S32 binding_count = 0;
+	S32 line_count = 0;
+
+	if(filename.empty())
+	{
+		LL_ERRS() << " No filename specified" << LL_ENDL;
+		return 0;
+	}
+
+	fp = LLFile::fopen(filename, "r");
+
+	if (!fp)
+	{
+		return 0;
+	}
+
+
+	while (!feof(fp))
+	{
+		line_count++;
+		if (!fgets(buffer, BUFFER_SIZE, fp))
+			break;
+
+		// skip over comments, blank lines
+		if (buffer[0] == '#' || buffer[0] == '\n') continue;
+
+		// grab the binding strings
+		tokens_read = sscanf(	/* Flawfinder: ignore */
+			buffer,
+			"%254s %254s %254s %254s",
+			mode_string,
+			key_string,
+			mask_string,
+			function_string);
+
+		if (tokens_read == EOF)
+		{
+			LL_INFOS() << "Unexpected end-of-file at line " << line_count << " of key binding file " << filename << LL_ENDL;
+			fclose(fp);
+			return 0;
+		}
+		else if (tokens_read < 4)
+		{
+			LL_INFOS() << "Can't read line " << line_count << " of key binding file " << filename << LL_ENDL;
+			continue;
+		}
+
+		// convert mode
+		if (!modeFromString(mode_string, &mode))
+		{
+			LL_INFOS() << "Unknown mode on line " << line_count << " of key binding file " << filename << LL_ENDL;
+			LL_INFOS() << "Mode must be one of FIRST_PERSON, THIRD_PERSON, EDIT, EDIT_AVATAR" << LL_ENDL;
+			continue;
+		}
+
+		// convert key
+		if (!LLKeyboard::keyFromString(key_string, &key))
+		{
+			LL_INFOS() << "Can't interpret key on line " << line_count << " of key binding file " << filename << LL_ENDL;
+			continue;
+		}
+
+		// convert mask
+		if (!LLKeyboard::maskFromString(mask_string, &mask))
+		{
+			LL_INFOS() << "Can't interpret mask on line " << line_count << " of key binding file " << filename << LL_ENDL;
+			continue;
+		}
+
+		// bind key
+		if (bindKey(mode, key, mask, function_string))
+		{
+			binding_count++;
+		}
+	}
+
+	fclose(fp);
+
+	return binding_count;
+}
+
+
+EKeyboardMode LLViewerKeyboard::getMode()
+{
+	if ( gAgentCamera.cameraMouselook() )
+	{
+		return MODE_FIRST_PERSON;
+	}
+	else if ( gMorphView && gMorphView->getVisible())
+	{
+		return MODE_EDIT_AVATAR;
+	}
+	else if (isAgentAvatarValid() && gAgentAvatarp->isSitting())
+	{
+		return MODE_SITTING;
+	}
+	else
+	{
+		return MODE_THIRD_PERSON;
+	}
+}
+
+
+// Called from scanKeyboard.
+void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
+{
+	if (LLApp::isExiting())
+	{
+		return;
+	}
+
+	S32 mode = getMode();
+	// Consider keyboard scanning as NOT mouse event. JC
+	MASK mask = gKeyboard->currentMask(FALSE);
+
+	LLKeyBinding* binding = mBindings[mode];
+	S32 binding_count = mBindingCount[mode];
+
+
+	if (mKeyHandledByUI[key])
+	{
+		return;
+	}
+
+	// don't process key down on repeated keys
+	BOOL repeat = gKeyboard->getKeyRepeated(key);
+
+	for (S32 i = 0; i < binding_count; i++)
+	{
+		//for (S32 key = 0; key < KEY_COUNT; key++)
+		if (binding[i].mKey == key)
+		{
+			//if (binding[i].mKey == key && binding[i].mMask == mask)
+			if (binding[i].mMask == mask)
+			{
+				if (key_down && !repeat)
+				{
+					// ...key went down this frame, call function
+					binding[i].mFunction( KEYSTATE_DOWN );
+				}
+				else if (key_up)
+				{
+					// ...key went down this frame, call function
+					binding[i].mFunction( KEYSTATE_UP );
+				}
+				else if (key_level)
+				{
+					// ...key held down from previous frame
+					// Not windows, just call the function.
+					binding[i].mFunction( KEYSTATE_LEVEL );
+				}//if
+			}//if
+		}//for
+	}//for
+}
diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h
new file mode 100644
index 0000000000..110dc89d28
--- /dev/null
+++ b/indra/newview/llviewerkeyboard.h
@@ -0,0 +1,118 @@
+/** 
+ * @file llviewerkeyboard.h
+ * @brief LLViewerKeyboard class header file
+ *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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_LLVIEWERKEYBOARD_H
+#define LL_LLVIEWERKEYBOARD_H
+
+#include "llkeyboard.h" // For EKeystate
+#include "llinitparam.h"
+
+const S32 MAX_NAMED_FUNCTIONS = 100;
+const S32 MAX_KEY_BINDINGS = 128; // was 60
+
+class LLNamedFunction
+{
+public:
+	LLNamedFunction() : mFunction(NULL) { };
+	~LLNamedFunction() { };
+
+	std::string	mName;
+	LLKeyFunc	mFunction;
+};
+
+typedef enum e_keyboard_mode
+{
+	MODE_FIRST_PERSON,
+	MODE_THIRD_PERSON,
+	MODE_EDIT,
+	MODE_EDIT_AVATAR,
+	MODE_SITTING,
+	MODE_COUNT
+} EKeyboardMode;
+
+
+void bind_keyboard_functions();
+
+class LLViewerKeyboard
+{
+public:
+	struct KeyBinding : public LLInitParam::Block<KeyBinding>
+	{
+		Mandatory<std::string>	key,
+								mask,
+								command;
+
+		KeyBinding();
+	};
+
+	struct KeyMode : public LLInitParam::Block<KeyMode>
+	{
+		Multiple<KeyBinding>		bindings;
+		EKeyboardMode				mode;
+		KeyMode(EKeyboardMode mode);
+	};
+
+	struct Keys : public LLInitParam::Block<Keys>
+	{
+		Optional<KeyMode>	first_person,
+							third_person,
+							edit,
+							sitting,
+							edit_avatar;
+
+		Keys();
+	};
+
+	LLViewerKeyboard();
+
+	BOOL			handleKey(KEY key, MASK mask, BOOL repeated);
+	BOOL			handleKeyUp(KEY key, MASK mask);
+
+	S32				loadBindings(const std::string& filename);										// returns number bound, 0 on error
+	S32				loadBindingsXML(const std::string& filename);										// returns number bound, 0 on error
+	EKeyboardMode	getMode();
+
+	BOOL			modeFromString(const std::string& string, S32 *mode);			// False on failure
+
+	void			scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level);
+
+private:
+	S32				loadBindingMode(const LLViewerKeyboard::KeyMode& keymode);
+	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
+	S32				mBindingCount[MODE_COUNT];
+	LLKeyBinding	mBindings[MODE_COUNT][MAX_KEY_BINDINGS];
+
+	typedef std::map<U32, U32> key_remap_t;
+	key_remap_t		mRemapKeys[MODE_COUNT];
+	std::set<KEY>	mKeysSkippedByUI;
+	BOOL			mKeyHandledByUI[KEY_COUNT];		// key processed successfully by UI
+};
+
+extern LLViewerKeyboard gViewerKeyboard;
+
+#endif // LL_LLVIEWERKEYBOARD_H
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index ab054fabde..b6c7be2ed3 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -8031,6 +8031,7 @@ BOOL LLViewerMenuHolderGL::hideMenus()
 	
 	if (LLMenuHolderGL::hideMenus())
 	{
+		LLToolPie::instance().blockClickToWalk();
 		handled = TRUE;
 	}
 
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 19c0c2d285..1fbb32ac5e 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -45,8 +45,7 @@
 #include "llmeshrepository.h"
 #include "llnotificationhandler.h"
 #include "llpanellogin.h"
-#include "llsetkeybinddialog.h"
-#include "llviewerinput.h"
+#include "llviewerkeyboard.h"
 #include "llviewermenu.h"
 
 #include "llviewquery.h"
@@ -174,7 +173,7 @@
 #include "llviewergesture.h"
 #include "llviewertexturelist.h"
 #include "llviewerinventory.h"
-#include "llviewerinput.h"
+#include "llviewerkeyboard.h"
 #include "llviewermedia.h"
 #include "llviewermediafocus.h"
 #include "llviewermenu.h"
@@ -915,18 +914,7 @@ LLViewerWindow::Params::Params()
 {}
 
 
-void LLViewerWindow::handlePieMenu(S32 x, S32 y, MASK mask)
-{
-    if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance() && gAgent.isInitialized())
-    {
-        // If the current tool didn't process the click, we should show
-        // the pie menu.  This can be done by passing the event to the pie
-        // menu tool.
-        LLToolPie::getInstance()->handleRightMouseDown(x, y, mask);
-    }
-}
-
-BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down)
+BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window,  LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down)
 {
 	const char* buttonname = "";
 	const char* buttonstatestr = "";
@@ -950,30 +938,28 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK m
 		
 		switch (clicktype)
 		{
-		case CLICK_LEFT:
+		case LLMouseHandler::CLICK_LEFT:
 			mLeftMouseDown = down;
 			buttonname = "Left";
 			break;
-		case CLICK_RIGHT:
+		case LLMouseHandler::CLICK_RIGHT:
 			mRightMouseDown = down;
 			buttonname = "Right";
 			break;
-		case CLICK_MIDDLE:
+		case LLMouseHandler::CLICK_MIDDLE:
 			mMiddleMouseDown = down;
 			buttonname = "Middle";
 			break;
-		case CLICK_DOUBLELEFT:
+		case LLMouseHandler::CLICK_DOUBLELEFT:
 			mLeftMouseDown = down;
 			buttonname = "Left Double Click";
 			break;
-		case CLICK_BUTTON4:
+		case LLMouseHandler::CLICK_BUTTON4:
 			buttonname = "Button 4";
 			break;
-		case CLICK_BUTTON5:
+		case LLMouseHandler::CLICK_BUTTON5:
 			buttonname = "Button 5";
 			break;
-		default:
-			break; // COUNT and NONE
 		}
 		
 		LLView::sMouseHandlerMessage.clear();
@@ -1024,11 +1010,6 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK m
 				LLViewerEventRecorder::instance().logMouseEvent(std::string(buttonstatestr),std::string(buttonname)); 
 
 			}
-			else if (down && clicktype == CLICK_RIGHT)
-			{
-				handlePieMenu(x, y, mask);
-				r = TRUE;
-			}
 			return r;
 		}
 
@@ -1075,12 +1056,7 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK m
 		return TRUE;
 	}
 
-	if (down && clicktype == CLICK_RIGHT)
-	{
-		handlePieMenu(x, y, mask);
-		return TRUE;
-	}
-
+	
 	// If we got this far on a down-click, it wasn't handled.
 	// Up-clicks, though, are always handled as far as the OS is concerned.
 	BOOL default_rtn = !down;
@@ -1099,8 +1075,7 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask
         mMouseDownTimer.reset();
     }    
     BOOL down = TRUE;
-    //handleMouse() loops back to LLViewerWindow::handleAnyMouseClick
-    return gViewerInput.handleMouse(window, pos, mask, CLICK_LEFT, down);
+	return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down);
 }
 
 BOOL LLViewerWindow::handleDoubleClick(LLWindow *window,  LLCoordGL pos, MASK mask)
@@ -1108,7 +1083,8 @@ 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 (gViewerInput.handleMouse(window, pos, mask, CLICK_DOUBLELEFT, down))
+	if (handleAnyMouseClick(window, pos, mask,
+				LLMouseHandler::CLICK_DOUBLELEFT, down))
 	{
 		return TRUE;
 	}
@@ -1122,24 +1098,47 @@ BOOL LLViewerWindow::handleMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)
         mMouseDownTimer.stop();
     }
     BOOL down = FALSE;
-    return gViewerInput.handleMouse(window, pos, mask, CLICK_LEFT, down);
+	return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down);
 }
+
+
 BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask)
 {
+	S32 x = pos.mX;
+	S32 y = pos.mY;
+	x = ll_round((F32)x / mDisplayScale.mV[VX]);
+	y = ll_round((F32)y / mDisplayScale.mV[VY]);
+
 	BOOL down = TRUE;
-	return gViewerInput.handleMouse(window, pos, mask, CLICK_RIGHT, down);
+	BOOL handle = handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down);
+	if (handle)
+		return handle;
+
+	// *HACK: this should be rolled into the composite tool logic, not
+	// hardcoded at the top level.
+	if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance() && gAgent.isInitialized())
+	{
+		// If the current tool didn't process the click, we should show
+		// the pie menu.  This can be done by passing the event to the pie
+		// menu tool.
+		LLToolPie::getInstance()->handleRightMouseDown(x, y, mask);
+		// show_context_menu( x, y, mask );
+	}
+
+	return TRUE;
 }
 
 BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)
 {
 	BOOL down = FALSE;
- 	return gViewerInput.handleMouse(window, pos, mask, CLICK_RIGHT, down);
+ 	return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down);
 }
 
 BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask)
 {
 	BOOL down = TRUE;
- 	gViewerInput.handleMouse(window, pos, mask, CLICK_MIDDLE, down);
+	LLVoiceClient::getInstance()->updateMouseState(LLMouseHandler::CLICK_MIDDLE, true);
+ 	handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);
   
   	// Always handled as far as the OS is concerned.
 	return TRUE;
@@ -1294,7 +1293,8 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi
 BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)
 {
 	BOOL down = FALSE;
- 	gViewerInput.handleMouse(window, pos, mask, CLICK_MIDDLE, down);
+	LLVoiceClient::getInstance()->updateMouseState(LLMouseHandler::CLICK_MIDDLE, false);
+ 	handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);
   
   	// Always handled as far as the OS is concerned.
 	return TRUE;
@@ -1305,10 +1305,12 @@ BOOL LLViewerWindow::handleOtherMouse(LLWindow *window, LLCoordGL pos, MASK mask
     switch (button)
     {
     case 4:
-        gViewerInput.handleMouse(window, pos, mask, CLICK_BUTTON4, down);
+        LLVoiceClient::getInstance()->updateMouseState(LLMouseHandler::CLICK_BUTTON4, down);
+        handleAnyMouseClick(window, pos, mask, LLMouseHandler::CLICK_BUTTON4, down);
         break;
     case 5:
-        gViewerInput.handleMouse(window, pos, mask, CLICK_BUTTON5, down);
+        LLVoiceClient::getInstance()->updateMouseState(LLMouseHandler::CLICK_BUTTON5, down);
+        handleAnyMouseClick(window, pos, mask, LLMouseHandler::CLICK_BUTTON5, down);
         break;
     default:
         break;
@@ -1454,6 +1456,9 @@ void LLViewerWindow::handleFocusLost(LLWindow *window)
 
 BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key,  MASK mask, BOOL repeated)
 {
+	// Let the voice chat code check for its PTT key.  Note that this never affects event processing.
+	LLVoiceClient::getInstance()->keyDown(key, mask);
+
 	if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME)
 	{
 		gAgent.clearAFK();
@@ -1472,12 +1477,14 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key,  MASK mask, BOOL repeated)
     		return FALSE;
 	}
 
-    // remaps, handles ignored cases and returns back to viewer window.
-    return gViewerInput.handleKey(key, mask, repeated);
+	return gViewerKeyboard.handleKey(key, mask, repeated);
 }
 
 BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key,  MASK mask)
 {
+	// Let the voice chat code check for its PTT key.  Note that this never affects event processing.
+	LLVoiceClient::getInstance()->keyUp(key, mask);
+
 	// Let the inspect tool code check for ALT key to set LLToolSelectRect active instead LLToolCamera
 	LLToolCompInspect * tool_inspectp = LLToolCompInspect::getInstance();
 	if (LLToolMgr::getInstance()->getCurrentTool() == tool_inspectp)
@@ -1485,13 +1492,13 @@ BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key,  MASK mask)
 		tool_inspectp->keyUp(key, mask);
 	}
 
-	return gViewerInput.handleKeyUp(key, mask);
+	return gViewerKeyboard.handleKeyUp(key, mask);
 }
 
 void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
 {
 	LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true);
-	gViewerInput.scanKey(key, key_down, key_up, key_level);
+	gViewerKeyboard.scanKey(key, key_down, key_up, key_level);
 	return; // Be clear this function returns nothing
 }
 
@@ -2731,14 +2738,6 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
 	// hide tooltips on keypress
 	LLToolTipMgr::instance().blockToolTips();
 
-    // let menus handle navigation keys for navigation
-    if (LLSetKeyBindDialog::recordKey(key, mask))
-    {
-        LL_DEBUGS() << "Key handled by LLSetKeyBindDialog" << LL_ENDL;
-        LLViewerEventRecorder::instance().logKeyEvent(key,mask);
-        return TRUE;
-    }
-
     LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
 
     if (keyboard_focus
@@ -2954,8 +2953,7 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
 	{
 		if (mask != MASK_ALT)
 		{
-			// remaps, handles ignored cases and returns back to viewer window.
-			return gViewerInput.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
+			return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
 		}
 	}
 
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 67e5e4b4d6..e901245f92 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -175,9 +175,8 @@ public:
 	void			initWorldUI();
 	void			setUIVisibility(bool);
 	bool			getUIVisibility();
-	void			handlePieMenu(S32 x, S32 y, MASK mask);
 
-	BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down);
+	BOOL handleAnyMouseClick(LLWindow *window,  LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down);
 
 	//
 	// LLWindowCallback interface implementation
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index fca8de7410..cc590fc947 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -200,6 +200,8 @@ const LLVoiceVersionInfo LLVoiceClient::getVersion()
 void LLVoiceClient::updateSettings()
 {
 	setUsePTT(gSavedSettings.getBOOL("PTTCurrentlyEnabled"));
+	std::string keyString = gSavedSettings.getString("PushToTalkButton");
+	setPTTKey(keyString);
 	setPTTIsToggle(gSavedSettings.getBOOL("PushToTalkToggle"));
 	mDisableMic = gSavedSettings.getBOOL("VoiceDisableMic");
 
@@ -635,6 +637,32 @@ bool LLVoiceClient::getPTTIsToggle()
 	return mPTTIsToggle;
 }
 
+void LLVoiceClient::setPTTKey(std::string &key)
+{
+	// Value is stored as text for readability
+	if(key == "MiddleMouse")
+	{
+		mPTTMouseButton = LLMouseHandler::CLICK_MIDDLE;
+	}
+	else if(key == "MouseButton4")
+	{
+		mPTTMouseButton = LLMouseHandler::CLICK_BUTTON4;
+	}
+	else if (key == "MouseButton5")
+	{
+		mPTTMouseButton = LLMouseHandler::CLICK_BUTTON5;
+	}
+	else
+	{
+		mPTTMouseButton = 0;
+		if(!LLKeyboard::keyFromString(key, &mPTTKey))
+		{
+			// If the call failed, don't match any key.
+			key = KEY_NONE;
+		}
+	}
+}
+
 void LLVoiceClient::inputUserControlState(bool down)
 {
 	if(mPTTIsToggle)
@@ -655,6 +683,43 @@ void LLVoiceClient::toggleUserPTTState(void)
 	setUserPTTState(!getUserPTTState());
 }
 
+void LLVoiceClient::keyDown(KEY key, MASK mask)
+{	
+	if (gKeyboard->getKeyRepeated(key))
+	{
+		// ignore auto-repeat keys                                                                         
+		return;
+	}
+	
+	if (mPTTMouseButton == 0 && LLAgent::isActionAllowed("speak") && (key == mPTTKey))
+	{
+		bool down = gKeyboard->getKeyDown(mPTTKey);
+		if (down)
+		{
+			inputUserControlState(down);
+		}
+	}
+	
+}
+void LLVoiceClient::keyUp(KEY key, MASK mask)
+{
+	if (mPTTMouseButton == 0 && (key == mPTTKey))
+	{
+		bool down = gKeyboard->getKeyDown(mPTTKey);
+		if (!down)
+		{
+			inputUserControlState(down);
+		}
+	}
+}
+void LLVoiceClient::updateMouseState(S32 click, bool down)
+{
+	if(mPTTMouseButton == click && LLAgent::isActionAllowed("speak"))
+	{
+		inputUserControlState(down);
+	}
+}
+
 
 //-------------------------------------------
 // nearby speaker accessors
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index cecaac7f85..3d04e1f0db 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -408,10 +408,16 @@ public:
 	void setUsePTT(bool usePTT);
 	void setPTTIsToggle(bool PTTIsToggle);
 	bool getPTTIsToggle();	
-
+	void setPTTKey(std::string &key);
+	
 	void updateMicMuteLogic();
-
+	
 	BOOL lipSyncEnabled();
+	
+	// PTT key triggering
+	void keyDown(KEY key, MASK mask);
+	void keyUp(KEY key, MASK mask);
+	void updateMouseState(S32 click, bool down);
 
 	boost::signals2::connection MicroChangedCallback(const micro_changed_signal_t::slot_type& cb ) { return mMicroChangedSignal.connect(cb); }
 
diff --git a/indra/newview/llwindowlistener.cpp b/indra/newview/llwindowlistener.cpp
index aa8c79b0d2..9e4297baaf 100644
--- a/indra/newview/llwindowlistener.cpp
+++ b/indra/newview/llwindowlistener.cpp
@@ -37,7 +37,7 @@
 #include "llview.h"
 #include "llviewinject.h"
 #include "llviewerwindow.h"
-#include "llviewerinput.h"
+#include "llviewerkeyboard.h"
 #include "llrootview.h"
 #include "llsdutil.h"
 #include "stringize.h"
@@ -279,7 +279,7 @@ void LLWindowListener::keyDown(LLSD const & evt)
 			response.setResponse(target_view->getInfo());
 			
 			gFocusMgr.setKeyboardFocus(target_view);
-			gViewerInput.handleKey(key, mask, false);
+			gViewerKeyboard.handleKey(key, mask, false);
 			if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
 		}
 		else 
@@ -291,7 +291,7 @@ void LLWindowListener::keyDown(LLSD const & evt)
 	}
 	else 
 	{
-		gViewerInput.handleKey(key, mask, false); 
+		gViewerKeyboard.handleKey(key, mask, false); 
 		if(key < 0x80) mWindow->handleUnicodeChar(key, mask);
 	}
 }
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_camera.xml b/indra/newview/skins/default/xui/en/control_table_contents_camera.xml
deleted file mode 100644
index aba81e3134..0000000000
--- a/indra/newview/skins/default/xui/en/control_table_contents_camera.xml
+++ /dev/null
@@ -1,178 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<contents>
-    <rows
-     enabled="false"
-     name="camera_actions"
-     value="">
-        <columns
-         type="icontext"
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         label="Camera"
-         name="lst_action"
-         value="Cam_FreeCam_Off" />
-    </rows>
-    <rows
-     name="look_up"
-     value="look_up">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Look Up" />
-    </rows>
-    <rows
-     name="look_down"
-     value="look_down">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Look Down" />
-    </rows>
-    <rows
-     name="move_forward"
-     value="move_forward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Forward" />
-    </rows>
-    <rows
-     name="move_backward"
-     value="move_backward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Backward" />
-    </rows>
-    <rows
-     name="move_forward_fast"
-     value="move_forward_fast">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Forward Fast" />
-    </rows>
-    <rows
-     name="move_backward_fast"
-     value="move_backward_fast">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Backward Fast" />
-    </rows>
-    <rows
-     name="spin_over"
-     value="spin_over">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Spin Over" />
-    </rows>
-    <rows
-     name="spin_under"
-     value="spin_under">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Spin Under" />
-    </rows>
-    <rows
-     name="pan_up"
-     value="pan_up">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan Up" />
-    </rows>
-    <rows
-     name="pan_down"
-     value="pan_down">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan Down" />
-    </rows>
-    <rows
-     name="pan_left"
-     value="pan_left">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan Left" />
-    </rows>
-    <rows
-     name="pan_right"
-     value="pan_right">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan Right" />
-    </rows>
-    <rows
-     name="pan_in"
-     value="pan_in">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan In" />
-    </rows>
-    <rows
-     name="pan_out"
-     value="pan_out">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Pan Out" />
-    </rows>
-    <rows
-     name="spin_around_ccw"
-     value="spin_around_ccw">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around counterclockwise"
-         value="Counterclockwise" />
-    </rows>
-    <rows
-     name="spin_around_cw"
-     value="spin_around_cw">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around clockwise"
-         value="Clockwise" />
-    </rows>
-</contents>
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_camera_sitting.xml b/indra/newview/skins/default/xui/en/control_table_contents_camera_sitting.xml
deleted file mode 100644
index 9334c6e179..0000000000
--- a/indra/newview/skins/default/xui/en/control_table_contents_camera_sitting.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<contents>
-    <rows
-     name="move_forward_sitting"
-     value="move_forward_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Forward Sitting" />
-    </rows>
-    <rows
-     name="move_backward_sitting"
-     value="move_backward_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Backward Sitting" />
-    </rows>
-    <rows
-     name="spin_over_sitting"
-     value="spin_over_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Spin Over Sitting" />
-    </rows>
-    <rows
-     name="spin_under_sitting"
-     value="spin_under_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Spin Under Sitting" />
-    </rows>
-    <rows
-     name="spin_around_ccw_sitting"
-     value="spin_around_ccw_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around counterclockwise sitting"
-         value="Counterclockwise Sitting" />
-    </rows>
-    <rows
-     name="spin_around_cw_sitting"
-     value="spin_around_cw_sitting">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around clockwise sitting"
-         value="Clockwise Sitting" />
-    </rows>
-</contents>
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_columns_basic.xml b/indra/newview/skins/default/xui/en/control_table_contents_columns_basic.xml
deleted file mode 100644
index e707aaf22c..0000000000
--- a/indra/newview/skins/default/xui/en/control_table_contents_columns_basic.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<contents>
-    <columns
-     relative_width="0.34"
-     label="Action"
-     name="lst_action" />
-    <columns
-     relative_width="0.22"
-     label="Primary Control"
-     name="lst_ctrl1" />
-    <columns
-     relative_width="0.22"
-     label="Alternate 1"
-     name="lst_ctrl2" />
-    <columns
-     relative_width="0.22"
-     label="Alternate 2"
-     name="lst_ctrl3" />
-</contents>
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_editing.xml b/indra/newview/skins/default/xui/en/control_table_contents_editing.xml
deleted file mode 100644
index 2a3314840a..0000000000
--- a/indra/newview/skins/default/xui/en/control_table_contents_editing.xml
+++ /dev/null
@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<contents>
-    <rows
-     enabled="false"
-     name="editing_actions"
-     value="">
-        <columns
-         type="icontext"
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         label="Editing"
-         name="lst_action"
-         value="Tool_Dozer" />
-    </rows>
-    <rows
-     name="edit_avatar_spin_ccw"
-     value="edit_avatar_spin_ccw">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around avatar counterclockwise"
-         value="Counterclockwise" />
-    </rows>
-    <rows
-     name="edit_avatar_spin_cw"
-     value="edit_avatar_spin_cw">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin around avatar clockwise"
-         value="Clockwise" />
-    </rows>
-    <rows
-     name="edit_avatar_spin_over"
-     value="edit_avatar_spin_over">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin over avatar"
-         value="Camera Spin Over" />
-    </rows>
-    <rows
-     name="edit_avatar_spin_under"
-     value="edit_avatar_spin_under">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Camera spin under avatar"
-         value="Camera Spin Under" />
-    </rows>
-    <rows
-     name="edit_avatar_move_forward"
-     value="edit_avatar_move_forward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Forward" />
-    </rows>
-    <rows
-     name="edit_avatar_move_backward"
-     value="edit_avatar_move_backward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Camera Backward" />
-    </rows>
-</contents>
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_media.xml b/indra/newview/skins/default/xui/en/control_table_contents_media.xml
deleted file mode 100644
index ce5d3556b6..0000000000
--- a/indra/newview/skins/default/xui/en/control_table_contents_media.xml
+++ /dev/null
@@ -1,76 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<contents>
-    <rows
-     enabled="false"
-     name="media_actions"
-     value="">
-        <columns
-         type="icontext"
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         label="Sound and Media"
-         name="lst_action"
-         value="Audio_Press" />
-    </rows>
-    <rows
-     name="toggle_pause_media"
-     value="toggle_pause_media">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Play/Pause Media" />
-    </rows>
-    <rows
-     name="toggle_enable_media"
-     value="toggle_enable_media">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Play/Stop All Media" />
-    </rows>
-    <rows
-     name="voice_follow_key"
-     value="voice_follow_key">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Voice" />
-    </rows>
-    <rows
-     name="toggle_voice"
-     value="toggle_voice">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Toggle Voice" />
-    </rows>
-    <rows
-     name="start_chat"
-     value="start_chat">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Start Chat" />
-    </rows>
-    <rows
-     name="start_gesture"
-     value="start_gesture">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Start Gesture" />
-    </rows>
-</contents>
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_movement.xml b/indra/newview/skins/default/xui/en/control_table_contents_movement.xml
deleted file mode 100644
index b410d2dc1c..0000000000
--- a/indra/newview/skins/default/xui/en/control_table_contents_movement.xml
+++ /dev/null
@@ -1,198 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<contents>
-    <rows
-     enabled="false"
-     name="move_actions"
-     value="">
-        <columns
-         type="icontext"
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         label="Move Actions"
-         name="lst_action"
-         value="Move_Walk_Off" />
-    </rows>
-    <rows
-     name="walk_to"
-     value="walk_to">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Walk to location mouse cursor points to"
-         value="Walk to" />
-    </rows>
-    <rows
-     name="teleport_to"
-     value="teleport_to">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         tool_tip="Teleport to location mouse cursor points to, but not all locations allow direct teleportation so you might be teleported closer to destination instead"
-         value="Teleport to" />
-    </rows>
-    <rows
-     name="push_forward"
-     value="push_forward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Move Forward" />
-    </rows>
-    <rows
-     name="push_backward"
-     value="push_backward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Move Backward" />
-    </rows>
-    <rows
-     name="turn_left"
-     value="turn_left">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Left" />
-    </rows>
-    <rows
-     name="turn_right"
-     value="turn_right">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Right" />
-    </rows>
-    <rows
-     name="slide_left"
-     value="slide_left">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Strafe left" />
-    </rows>
-    <rows
-     name="slide_right"
-     value="slide_right">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Strafe right" />
-    </rows>
-    <rows
-     name="jump"
-     value="jump">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Jump/Up" />
-    </rows>
-    <rows
-     name="push_down"
-     value="push_down">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Down" />
-    </rows>
-    <rows
-     name="run_forward"
-     value="run_forward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Run Forward" />
-    </rows>
-    <rows
-     name="run_backward"
-     value="run_backward">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Run Backward" />
-    </rows>
-    <rows
-     name="run_left"
-     value="run_left">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Run Left" />
-    </rows>
-    <rows
-     name="run_right"
-     value="run_right">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Run Right" />
-    </rows>
-    <rows
-     name="toggle_run"
-     value="toggle_run">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Toggle Run" />
-    </rows>
-    <rows
-     name="toggle_fly"
-     value="toggle_fly">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Fly/Stop flying" />
-    </rows>
-    <rows
-     name="toggle_sit"
-     value="toggle_sit">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Sit/Stand" />
-    </rows>
-    <rows
-     name="stop_moving"
-     value="stop_moving">
-        <columns
-         column="lst_action"
-         font="SansSerif"
-         halign="left"
-         name="lst_action"
-         value="Stop Moving" />
-    </rows>
-</contents>
diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml
index ee730dcb01..0e62d50072 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences.xml
@@ -169,13 +169,6 @@ https://accounts.secondlife.com/change_email/
          layout="topleft"
          help_topic="preferences_uploads_tab"
          name="uploads" />
-        <panel
-         class="panel_preference_controls"
-         filename="panel_preferences_controls.xml"
-         label="Controls"
-         layout="topleft"
-         help_topic="preferences_controls_tab"
-         name="controls" />
     </tab_container>
 
 </floater>
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 48d9eee4cd..4e89df5a73 100644
--- a/indra/newview/skins/default/xui/en/floater_select_key.xml
+++ b/indra/newview/skins/default/xui/en/floater_select_key.xml
@@ -4,27 +4,10 @@
  border="false"
  can_close="false"
  can_minimize="false"
- height="116"
+ height="90"
  layout="topleft"
  name="modal container"
- width="272">
-  <floater.string
-   name="keyboard">
-    Keyboard
-  </floater.string>
-  <floater.string
-   name="mouse">
-    Mouse Buttons
-  </floater.string>
-  <floater.string
-   name="basic_description">
-Press a key to set your trigger.
-Allowed input: [INPUT].
-  </floater.string>
-  <floater.string
-   name="reserved_by_menu">
-Combination [KEYSTR] is reserved by menu.
-  </floater.string>
+ width="240">
     <text
      type="string"
      halign="center"
@@ -33,47 +16,19 @@ Combination [KEYSTR] is reserved by menu.
      height="30"
      layout="topleft"
      left="30"
-     name="descritption"
+     name="Save item as:"
      top="25"
      word_wrap="true"
-     width="212">
-Press a key to set your trigger.
-Allowed input: [INPUT].
+     width="180">
+        Press a key to set your Speak button trigger.
     </text>
-    <check_box
-     follows="top|left"
-     height="20"
-     initial_value="false"
-     label="Apply to all"
-     layout="topleft"
-     left="90"
-     name="apply_all"
-     tool_tip="Viewer uses different control combinations depending on what you are doing in world, setting this will apply your change to all combinations"
-     top_pad="8"
-     width="160" />
-  
-    <button
-     height="23"
-     label="Set Empty"
-     layout="topleft"
-     left="8"
-     name="SetEmpty"
-     top_pad="6"
-     width="80" />
-    <button
-     height="23"
-     label="Default"
-     layout="topleft"
-     left_pad="8"
-     name="Default"
-     top_delta="0"
-     width="80" />
     <button
      height="23"
      label="Cancel"
+     label_selected="Cancel"
      layout="topleft"
-     left_pad="8"
+     right="-10"
      name="Cancel"
-     top_delta="0"
-     width="80" />
+     top_pad="8"
+     width="100" />
 </floater>
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 6cc91d2cce..32ae56e3af 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -11408,19 +11408,6 @@ Cannot create large prims that intersect other residents.  Please re-try when ot
      notext="Cancel"
      yestext="OK"/>
   </notification>
-  
-  <notification
-   icon="alertmodal.tga"
-   name="PreferenceControlsDefaults"
-   type="alertmodal">
-    Do you want to restore default values for controls?
-    <tag>confirm</tag>
-    <usetemplate
-       canceltext="Cancel"
-       name="yesnocancelbuttons"
-       notext="Current mode"
-       yestext="All modes"/>
-  </notification>
     
   <notification
    icon="alertmodal.tga"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
deleted file mode 100644
index 904387909e..0000000000
--- a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<panel
- border="true"
- follows="all"
- height="408"
- label="Controls"
- layout="topleft"
- left="102"
- name="controls"
- top="1"
- width="517">
-  <combo_box
-   follows="top|left"
-   layout="topleft"
-   top="6"
-   left="10"
-   height="23"
-   width="140"
-   name="key_mode">
-    <combo_box.item
-     label="Third Person "
-     name="third_person"
-     value="1"/>
-    <combo_box.item
-     label="First Person (Mouselook)"
-     name="first_person"
-     value="0"/>
-    <combo_box.item
-     label="Edit Avatar"
-     name="edit_avatar"
-     value="2"/>
-    <combo_box.item
-     label="Sitting"
-     name="sitting"
-     value="3"/>
-  </combo_box>
-
-  <button
-   follows="top|left"
-   layout="topleft"
-   top="6"
-   right="-10"
-   height="23"
-   width="140"
-   label="Restore Defaults"
-   tool_tip="Restores default values for all control modes."
-   name="restore_defaults"/>
-
-  <scroll_list
-   draw_heading="true"
-   follows="all"
-   layout="topleft"
-   column_padding="0"
-   selection_type="header"
-   top="31"
-   left="3"
-   bottom="-3"
-   right="-3"
-   can_sort="false"
-   multi_select="false"
-   name="controls_list"
-   fg_disable_color="ScrollUnselectedColor"/>
-</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
index 74c9b10cff..c2defdd772 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
@@ -463,13 +463,52 @@
   enabled_control="EnableVoiceChat"
   control_name="PushToTalkToggle"
   height="15"
-  label="Toggle speak on/off when I press button in toolbar"
+  label="Toggle speak on/off when I press:"
   layout="topleft"
   left="44"
   name="push_to_talk_toggle_check"
   width="237"
   tool_tip="When in toggle mode, press and release the trigger key ONCE to switch your microphone on or off. When not in toggle mode, the microphone broadcasts your voice only while the trigger is being held down."
   top_pad="3"/>
+  <line_editor
+   follows="top|left"
+   control_name="PushToTalkButton"
+   enabled="false"
+   enabled_control="EnableVoiceChat"
+   height="23"
+   left="80"
+   max_length_bytes="200"
+   name="modifier_combo"
+   label="Push-to-Speak trigger"
+   top_pad="3"
+   width="200" />
+  <button
+   layout="topleft"
+   follows="top|left"
+   enabled_control="EnableVoiceChat"
+   height="23"
+   label="Set Key"
+   left_pad="5"
+   name="set_voice_hotkey_button"
+   width="100">
+    <button.commit_callback
+    function="Pref.VoiceSetKey" />
+  </button>
+  <button
+     enabled_control="EnableVoiceChat"
+     follows="top|left"
+     halign="center"
+     height="23"
+     image_overlay="Refresh_Off"
+     layout="topleft"
+     tool_tip="Reset to Middle Mouse Button"
+     mouse_opaque="true"
+     name="set_voice_middlemouse_button"
+     left_pad="5"
+     width="25">
+    <button.commit_callback
+    function="Pref.VoiceSetMiddleMouse" />
+  </button>
   <button
    control_name="ShowDeviceSettings"
    follows="left|top"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index cd639ded36..1bfac6aeb7 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -4088,15 +4088,6 @@ Try enclosing path to the editor with double quotes.
   <string name="Z">Z</string>
   <!-- Key names end -->
 
-  <!-- Mouse button names (short) begin -->
-  <string name="LMB">LMB</string>
-  <string name="MMB">MMB</string>
-  <string name="RMB">RMB</string>
-  <string name="MB4">MB4</string>
-  <string name="MB5">MB5</string>
-  <string name="Double LMB">Double LMB</string>
-  <!-- Mouse button names end -->
-
   <!-- llviewerwindow -->
   <string name="BeaconParticle">Viewing particle beacons (blue)</string>
   <string name="BeaconPhysical">Viewing physical object beacons (green)</string>
-- 
cgit v1.2.3


From ebfa7a7992517278c3e095a0bd53ab81bfcdb847 Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Mon, 29 Jun 2020 21:29:16 +0300
Subject: SL-13467 Make LLTrace::BlockTimerStatHandle keys unique

Original commit in Nat's repo: https://bitbucket.org/lindenlab/viewer-vs2017-git/commits/f627140cf11232bab11fdfaf66c78544cf44f3e8
---
 indra/llinventory/llsettingsdaycycle.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/indra/llinventory/llsettingsdaycycle.cpp b/indra/llinventory/llsettingsdaycycle.cpp
index 457e5b7478..a687fd840d 100644
--- a/indra/llinventory/llsettingsdaycycle.cpp
+++ b/indra/llinventory/llsettingsdaycycle.cpp
@@ -41,8 +41,8 @@
 //=========================================================================
 namespace
 {
-    LLTrace::BlockTimerStatHandle FTM_BLEND_WATERVALUES("Blending Water Environment");
-    LLTrace::BlockTimerStatHandle FTM_UPDATE_WATERVALUES("Update Water Environment");
+    LLTrace::BlockTimerStatHandle FTM_BLEND_WATERVALUES("Blending Water Environment Day");
+    LLTrace::BlockTimerStatHandle FTM_UPDATE_WATERVALUES("Update Water Environment Day");
 
     template<typename T>
     inline T get_wrapping_distance(T begin, T end)
-- 
cgit v1.2.3


From 25e6dc4adb332cd65ea42bb3cea2160a9b8c393e Mon Sep 17 00:00:00 2001
From: Rider Linden <rider@lindenlab.com>
Date: Wed, 20 May 2020 15:37:21 -0700
Subject: SL-9756: Take the "session_id" from the offline message that was
 passed.

---
 indra/newview/llimprocessing.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp
index 6da7bbe263..b534fc0b4a 100644
--- a/indra/newview/llimprocessing.cpp
+++ b/indra/newview/llimprocessing.cpp
@@ -1608,7 +1608,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url)
             message_data["to_agent_id"].asUUID(),
             IM_OFFLINE,
             (EInstantMessage)message_data["dialog"].asInteger(),
-            LLUUID::null, // session id, since there is none we can only use frienship/group invite caps
+            message_data["session_id"].asUUID(),
             message_data["timestamp"].asInteger(),
             message_data["from_agent_name"].asString(),
             message_data["message"].asString(),
-- 
cgit v1.2.3


From 9887af162b1a5c4507d89d3f0d1392da7ee52b50 Mon Sep 17 00:00:00 2001
From: Rider Linden <rider@lindenlab.com>
Date: Mon, 8 Jun 2020 11:28:05 -0700
Subject: SL-11430, SL-9756: Take transaction-id from offline messages. 
 Correct LLSD names. Use offline flag rather than implicit tests of session_id
 and aux_id.

---
 indra/newview/llimprocessing.cpp | 61 +++++++++++++++++++++++-----------------
 1 file changed, 35 insertions(+), 26 deletions(-)

diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp
index b534fc0b4a..60f1de4e8c 100644
--- a/indra/newview/llimprocessing.cpp
+++ b/indra/newview/llimprocessing.cpp
@@ -857,7 +857,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
             }
             else // IM_TASK_INVENTORY_OFFERED
             {
-                if (offline == IM_OFFLINE && session_id.isNull() && aux_id.notNull() && binary_bucket_size > sizeof(S8)* 5)
+                if (offline)
                 {
                     // cap received offline message
                     std::string str_bucket = ll_safe_string((char*)binary_bucket, binary_bucket_size);
@@ -889,9 +889,10 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
             info->mIM = dialog;
             info->mFromID = from_id;
             info->mFromGroup = from_group;
-            info->mTransactionID = session_id;
             info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType));
 
+            info->mTransactionID = session_id.notNull() ? session_id : aux_id;
+
             info->mFromName = name;
             info->mDesc = message;
             info->mHost = sender;
@@ -1569,7 +1570,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url)
         return;
     }
 
-    if (gAgent.getRegion() == NULL)
+    if (!gAgent.getRegion())
     {
         LL_WARNS("Messaging") << "Region null while attempting to load messages." << LL_ENDL;
         return;
@@ -1577,8 +1578,8 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url)
 
     LL_INFOS("Messaging") << "Processing offline messages." << LL_ENDL;
 
-    std::vector<U8> data;
-    S32 binary_bucket_size = 0;
+//     std::vector<U8> data;
+//     S32 binary_bucket_size = 0;
     LLHost sender = gAgent.getRegionHost();
 
     LLSD::array_iterator i = messages.beginArray();
@@ -1587,38 +1588,46 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url)
     {
         const LLSD &message_data(*i);
 
-        LLVector3 position(message_data["local_x"].asReal(), message_data["local_y"].asReal(), message_data["local_z"].asReal());
-        data = message_data["binary_bucket"].asBinary();
-        binary_bucket_size = data.size(); // message_data["count"] always 0
-        U32 parent_estate_id = message_data.has("parent_estate_id") ? message_data["parent_estate_id"].asInteger() : 1; // 1 - IMMainland
+        /* RIDER: Many fields in this message are using a '_' rather than the standard '-'.  This 
+         * should be changed but would require tight coordination with the simulator. 
+         */
+        LLVector3 position;
+        if (message_data.has("position"))
+        {
+            position.setValue(message_data["position"]);
+        }
+        else
+        {
+            position.set(message_data["local_x"].asReal(), message_data["local_y"].asReal(), message_data["local_z"].asReal());
+        }
 
-        // Todo: once dirtsim-369 releases, remove one of the int/str options
-        BOOL from_group;
-        if (message_data["from_group"].isInteger())
+        std::vector<U8> bin_bucket;
+        if (message_data.has("binary_bucket"))
         {
-            from_group = message_data["from_group"].asInteger();
+            bin_bucket = message_data["binary_bucket"].asBinary();
         }
         else
         {
-            from_group = message_data["from_group"].asString() == "Y";
+            bin_bucket.push_back(0);
         }
 
-        LLIMProcessing::processNewMessage(message_data["from_agent_id"].asUUID(),
-            from_group,
+        LLIMProcessing::processNewMessage(
+            message_data["from_id"].asUUID(),
+            message_data["from_group"].asBoolean(),
             message_data["to_agent_id"].asUUID(),
-            IM_OFFLINE,
-            (EInstantMessage)message_data["dialog"].asInteger(),
-            message_data["session_id"].asUUID(),
-            message_data["timestamp"].asInteger(),
-            message_data["from_agent_name"].asString(),
-            message_data["message"].asString(),
-            parent_estate_id,
+            static_cast<U8>(message_data["offline"].asInteger()),
+            static_cast<EInstantMessage>(message_data["dialog"].asInteger()),
+            message_data["transaction-id"].asUUID(),
+            static_cast<U32>(message_data["timestamp"].asInteger()),
+            message_data["from_name"].asString(),
+            (message_data.has("message")) ? message_data["message"].asString() : std::string(),
+            static_cast<U32>((message_data.has("parent_estate_id")) ? message_data["parent_estate_id"].asInteger() : 1), // 1 - IMMainland
             message_data["region_id"].asUUID(),
             position,
-            &data[0],
-            binary_bucket_size,
+            bin_bucket.data(),
+            bin_bucket.size(),
             sender,
-            message_data["asset_id"].asUUID()); // not necessarily an asset
+            message_data["asset_id"].asUUID());
     }
 }
 
-- 
cgit v1.2.3


From 5f9a18c88f36897df025242921b319a2b84404c4 Mon Sep 17 00:00:00 2001
From: Rider Linden <rider@lindenlab.com>
Date: Thu, 18 Jun 2020 12:56:00 -0700
Subject: SL-9756: Get session_id/transaction id from aux if session is
 missing.

---
 indra/newview/llimprocessing.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp
index 60f1de4e8c..c274267b21 100644
--- a/indra/newview/llimprocessing.cpp
+++ b/indra/newview/llimprocessing.cpp
@@ -1628,6 +1628,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url)
             bin_bucket.size(),
             sender,
             message_data["asset_id"].asUUID());
+
     }
 }
 
-- 
cgit v1.2.3


From 8bf2078e90a6301d58581135a5d26362186ec0e8 Mon Sep 17 00:00:00 2001
From: Rider Linden <rider@lindenlab.com>
Date: Mon, 22 Jun 2020 10:55:05 -0700
Subject: SL-9756: IM_TASK_INVENTORY_OFFERED bucket offline format conforms to
 the online format.

---
 indra/newview/llimprocessing.cpp | 32 +++++++-------------------------
 1 file changed, 7 insertions(+), 25 deletions(-)

diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp
index c274267b21..a2900c553c 100644
--- a/indra/newview/llimprocessing.cpp
+++ b/indra/newview/llimprocessing.cpp
@@ -857,33 +857,15 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
             }
             else // IM_TASK_INVENTORY_OFFERED
             {
-                if (offline)
+                if (sizeof(S8) != binary_bucket_size)
                 {
-                    // cap received offline message
-                    std::string str_bucket = ll_safe_string((char*)binary_bucket, binary_bucket_size);
-                    typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
-                    boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
-                    tokenizer tokens(str_bucket, sep);
-                    tokenizer::iterator iter = tokens.begin();
-
-                    info->mType = (LLAssetType::EType)(atoi((*(iter++)).c_str()));
-                    // Note There is more elements in 'tokens' ...
-
-                    info->mObjectID = LLUUID::null;
-                    info->mFromObject = TRUE;
-                }
-                else
-                {
-                    if (sizeof(S8) != binary_bucket_size)
-                    {
-                        LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL;
-                        delete info;
-                        break;
-                    }
-                    info->mType = (LLAssetType::EType) binary_bucket[0];
-                    info->mObjectID = LLUUID::null;
-                    info->mFromObject = TRUE;
+                    LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL;
+                    delete info;
+                    break;
                 }
+                info->mType = (LLAssetType::EType) binary_bucket[0];
+                info->mObjectID = LLUUID::null;
+                info->mFromObject = TRUE;
             }
 
             info->mIM = dialog;
-- 
cgit v1.2.3


From 52f888b8d34483f8c9158d2ce7aaec33731ee1f5 Mon Sep 17 00:00:00 2001
From: Rider Linden <rider@lindenlab.com>
Date: Mon, 22 Jun 2020 16:08:11 -0700
Subject: SL-9756: Get the LLSD names right.

---
 indra/newview/llimprocessing.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp
index a2900c553c..fc209c2eae 100644
--- a/indra/newview/llimprocessing.cpp
+++ b/indra/newview/llimprocessing.cpp
@@ -1594,7 +1594,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url)
         }
 
         LLIMProcessing::processNewMessage(
-            message_data["from_id"].asUUID(),
+            message_data["from_agent_id"].asUUID(),
             message_data["from_group"].asBoolean(),
             message_data["to_agent_id"].asUUID(),
             static_cast<U8>(message_data["offline"].asInteger()),
-- 
cgit v1.2.3


From d9a03b55ff10b54a61ee6ed162f549399fc0f464 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 30 Jun 2020 23:53:48 +0300
Subject: SL-12085 Way to debug window message processing with logcontrol

---
 indra/llwindow/llwindowwin32.cpp  | 42 ++++++++++++++++++++++-----------------
 indra/newview/llviewerdisplay.cpp |  4 ++++
 2 files changed, 28 insertions(+), 18 deletions(-)

diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index d3cf1d49e4..7783505c27 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -1948,6 +1948,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
 	LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLongPtr( h_wnd, GWLP_USERDATA );
 
+	bool debug_window_proc = gDebugWindowProc || debugLoggingEnabled("Window");
+
 
 	if (NULL != window_imp)
 	{
@@ -1990,9 +1992,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
 		case WM_DEVICECHANGE:
 			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DEVICECHANGE");
-			if (gDebugWindowProc)
+			if (debug_window_proc)
 			{
-				LL_INFOS() << "  WM_DEVICECHANGE: wParam=" << w_param 
+				LL_INFOS("Window") << "  WM_DEVICECHANGE: wParam=" << w_param 
 						<< "; lParam=" << l_param << LL_ENDL;
 			}
 			if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL)
@@ -2048,7 +2050,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 				BOOL activating = (BOOL) w_param;
 				BOOL minimized = window_imp->getMinimized();
 
-				if (gDebugWindowProc)
+				if (debug_window_proc)
 				{
 					LL_INFOS("Window") << "WINDOWPROC ActivateApp "
 						<< " activating " << S32(activating)
@@ -2099,7 +2101,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 				// JC - I'm not sure why, but if we don't report that we handled the 
 				// WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work 
 				// properly when we run fullscreen.
-				if (gDebugWindowProc)
+				if (debug_window_proc)
 				{
 					LL_INFOS("Window") << "WINDOWPROC Activate "
 						<< " activating " << S32(activating) 
@@ -2171,7 +2173,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
 			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYDOWN");
 			{
-				if (gDebugWindowProc)
+				if (debug_window_proc)
 				{
 					LL_INFOS("Window") << "Debug WindowProc WM_KEYDOWN "
 						<< " key " << S32(w_param) 
@@ -2197,7 +2199,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYUP");
 			LL_RECORD_BLOCK_TIME(FTM_KEYHANDLER);
 
-			if (gDebugWindowProc)
+			if (debug_window_proc)
 			{
 				LL_INFOS("Window") << "Debug WindowProc WM_KEYUP "
 					<< " key " << S32(w_param) 
@@ -2213,9 +2215,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 		}
 		case WM_IME_SETCONTEXT:
 			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_SETCONTEXT");
-			if (gDebugWindowProc)
+			if (debug_window_proc)
 			{
-				LL_INFOS() << "WM_IME_SETCONTEXT" << LL_ENDL;
+				LL_INFOS("Window") << "WM_IME_SETCONTEXT" << LL_ENDL;
 			}
 			if (LLWinImm::isAvailable() && window_imp->mPreeditor)
 			{
@@ -2226,7 +2228,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
 		case WM_IME_STARTCOMPOSITION:
 			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_STARTCOMPOSITION");
-			if (gDebugWindowProc)
+			if (debug_window_proc)
 			{
 				LL_INFOS() << "WM_IME_STARTCOMPOSITION" << LL_ENDL;
 			}
@@ -2239,7 +2241,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
 		case WM_IME_ENDCOMPOSITION:
 			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_ENDCOMPOSITION");
-			if (gDebugWindowProc)
+			if (debug_window_proc)
 			{
 				LL_INFOS() << "WM_IME_ENDCOMPOSITION" << LL_ENDL;
 			}
@@ -2251,7 +2253,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
 		case WM_IME_COMPOSITION:
 			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_COMPOSITION");
-			if (gDebugWindowProc)
+			if (debug_window_proc)
 			{
 				LL_INFOS() << "WM_IME_COMPOSITION" << LL_ENDL;
 			}
@@ -2264,7 +2266,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
 		case WM_IME_REQUEST:
 			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_REQUEST");
-			if (gDebugWindowProc)
+			if (debug_window_proc)
 			{
 				LL_INFOS() << "WM_IME_REQUEST" << LL_ENDL;
 			}
@@ -2295,7 +2297,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 			// characters.  We just need to take care of surrogate pairs sent as two WM_CHAR's
 			// by ourselves.  It is not that tough.  -- Alissa Sabre @ SL
 			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CHAR");
-			if (gDebugWindowProc)
+			if (debug_window_proc)
 			{
 				LL_INFOS("Window") << "Debug WindowProc WM_CHAR "
 					<< " key " << S32(w_param) 
@@ -2738,7 +2740,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 				S32 width = S32( LOWORD(l_param) );
 				S32 height = S32( HIWORD(l_param) );
 
-				if (gDebugWindowProc)
+				if (debug_window_proc)
 				{
 					BOOL maximized = ( w_param == SIZE_MAXIMIZED );
 					BOOL restored  = ( w_param == SIZE_RESTORED );
@@ -2813,7 +2815,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 			}
 
 		case WM_SETFOCUS:
-			if (gDebugWindowProc)
+			if (debug_window_proc)
 			{
 				LL_INFOS("Window") << "WINDOWPROC SetFocus" << LL_ENDL;
 			}
@@ -2822,7 +2824,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 			return 0;
 
 		case WM_KILLFOCUS:
-			if (gDebugWindowProc)
+			if (debug_window_proc)
 			{
 				LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL;
 			}
@@ -2854,7 +2856,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 			break;
 		default:
 			{
-				if (gDebugWindowProc)
+				if (debug_window_proc)
 				{
 					LL_INFOS("Window") << "Unhandled windows message code: " << U32(u_msg) << LL_ENDL;
 				}
@@ -2864,7 +2866,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
 	window_imp->mCallbacks->handlePauseWatchdog(window_imp);	
 	}
-
+    else
+    {
+        // (NULL == window_imp)
+        LL_DEBUGS("Window") << "No window implementation to handle message with, message code: " << U32(u_msg) << LL_ENDL;
+    }
 
 	// pass unhandled messages down to Windows
 	return DefWindowProc(h_wnd, u_msg, w_param, l_param);
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 4c7eb41418..f025863072 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -151,6 +151,10 @@ void display_startup()
 	{
 		LLViewerDynamicTexture::updateAllInstances();
 	}
+    else
+    {
+        LL_DEBUGS("Window") << "First display_startup frame" << LL_ENDL;
+    }
 
 	LLGLState::checkStates();
 	LLGLState::checkTextureChannels();
-- 
cgit v1.2.3


From 2a70664c0db7b3681a7eb6979fcc2a8530ad6df1 Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Thu, 2 Jul 2020 02:54:43 +0300
Subject: Updated llca to build 544371

---
 autobuild.xml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/autobuild.xml b/autobuild.xml
index 803e479078..34d90393e7 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -2175,16 +2175,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>dd008981cac7ede93efa6cefe4ee61a0</string>
+              <string>25db349f18fc1e79f76ab3ba2c8d1330</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12484/73813/llca-201801172118.511910-common-511910.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62723/591962/llca-202007011528.544371-common-544371.tar.bz2</string>
             </map>
             <key>name</key>
             <string>common</string>
           </map>
         </map>
         <key>version</key>
-        <string>201801172118.511910</string>
+        <string>202007011528.544371</string>
       </map>
       <key>llphysicsextensions_source</key>
       <map>
-- 
cgit v1.2.3


From 3379259ffbc5bac0bf19097f1e83c137095be9ba Mon Sep 17 00:00:00 2001
From: Rider Linden <rider@lindenlab.com>
Date: Wed, 1 Jul 2020 16:52:44 -0700
Subject: SL-13533: Use the old name for from_agent_name SL-13540: Do not fail
 if binary bucket is too large, attempt to extract the asset type from the old
 style bucket. Notification still not shown.

---
 indra/newview/llimprocessing.cpp | 29 ++++++++++++++++++++++-------
 1 file changed, 22 insertions(+), 7 deletions(-)

diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp
index fc209c2eae..301b4c9214 100644
--- a/indra/newview/llimprocessing.cpp
+++ b/indra/newview/llimprocessing.cpp
@@ -857,13 +857,28 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
             }
             else // IM_TASK_INVENTORY_OFFERED
             {
-                if (sizeof(S8) != binary_bucket_size)
+                if (sizeof(S8) == binary_bucket_size)
                 {
-                    LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL;
-                    delete info;
-                    break;
+                    info->mType = (LLAssetType::EType) binary_bucket[0];
+                }
+                else
+                {
+                    /*RIDER*/ // The previous version of the protocol returned the wrong binary bucket... we 
+                    // still might be able to figure out the type... even though the offer is not retrievable. 
+                    std::string str_bucket(reinterpret_cast<char *>(binary_bucket));
+                    std::string str_type(str_bucket.substr(0, str_bucket.find('|')));
+
+                    std::stringstream type_convert(str_type);
+
+                    S32 type;
+                    type_convert >> type;
+
+                    // We could try AT_UNKNOWN which would be more accurate, but that causes an auto decline
+                    info->mType = static_cast<LLAssetType::EType>(type);
+                    // Don't break in the case of a bad binary bucket.  Go ahead and show the 
+                    // accept/decline popup even though it will not do anything.
+                    LL_WARNS("Messaging") << "Malformed inventory offer from object, type might be " << info->mType << LL_ENDL;
                 }
-                info->mType = (LLAssetType::EType) binary_bucket[0];
                 info->mObjectID = LLUUID::null;
                 info->mFromObject = TRUE;
             }
@@ -1601,8 +1616,8 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url)
             static_cast<EInstantMessage>(message_data["dialog"].asInteger()),
             message_data["transaction-id"].asUUID(),
             static_cast<U32>(message_data["timestamp"].asInteger()),
-            message_data["from_name"].asString(),
-            (message_data.has("message")) ? message_data["message"].asString() : std::string(),
+            message_data["from_agent_name"].asString(),
+            message_data["message"].asString(),
             static_cast<U32>((message_data.has("parent_estate_id")) ? message_data["parent_estate_id"].asInteger() : 1), // 1 - IMMainland
             message_data["region_id"].asUUID(),
             position,
-- 
cgit v1.2.3


From 7c122757f9ed2bd3b7ba033905db1dcb143eec6d Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 2 Jul 2020 13:03:57 +0300
Subject: SL-13540 Offline scripted inventory offers not shown on non
 drtsim-451

---
 indra/newview/llimprocessing.cpp | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp
index 301b4c9214..5c9d53e0b9 100644
--- a/indra/newview/llimprocessing.cpp
+++ b/indra/newview/llimprocessing.cpp
@@ -865,6 +865,8 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
                 {
                     /*RIDER*/ // The previous version of the protocol returned the wrong binary bucket... we 
                     // still might be able to figure out the type... even though the offer is not retrievable. 
+
+                    // Should be safe to remove once DRTSIM-451 fully deploys
                     std::string str_bucket(reinterpret_cast<char *>(binary_bucket));
                     std::string str_type(str_bucket.substr(0, str_bucket.find('|')));
 
@@ -1575,8 +1577,6 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url)
 
     LL_INFOS("Messaging") << "Processing offline messages." << LL_ENDL;
 
-//     std::vector<U8> data;
-//     S32 binary_bucket_size = 0;
     LLHost sender = gAgent.getRegionHost();
 
     LLSD::array_iterator i = messages.beginArray();
@@ -1608,11 +1608,22 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url)
             bin_bucket.push_back(0);
         }
 
+        // Todo: once drtsim-451 releases, remove the string option
+        BOOL from_group;
+        if (message_data["from_group"].isInteger())
+        {
+            from_group = message_data["from_group"].asInteger();
+        }
+        else
+        {
+            from_group = message_data["from_group"].asString() == "Y";
+        }
+
         LLIMProcessing::processNewMessage(
             message_data["from_agent_id"].asUUID(),
-            message_data["from_group"].asBoolean(),
+            from_group,
             message_data["to_agent_id"].asUUID(),
-            static_cast<U8>(message_data["offline"].asInteger()),
+            message_data.has("offline") ? static_cast<U8>(message_data["offline"].asInteger()) : IM_OFFLINE,
             static_cast<EInstantMessage>(message_data["dialog"].asInteger()),
             message_data["transaction-id"].asUUID(),
             static_cast<U32>(message_data["timestamp"].asInteger()),
-- 
cgit v1.2.3


From fa1ae9fa1adfdaaa79c3093cf628eb08a99575bb Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 3 Jul 2020 20:40:41 +0300
Subject: SL-13540 Fix line endings

---
 indra/newview/llimprocessing.cpp | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp
index 5c9d53e0b9..79cf49ddb1 100644
--- a/indra/newview/llimprocessing.cpp
+++ b/indra/newview/llimprocessing.cpp
@@ -1608,15 +1608,15 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url)
             bin_bucket.push_back(0);
         }
 
-        // Todo: once drtsim-451 releases, remove the string option
-        BOOL from_group;
-        if (message_data["from_group"].isInteger())
-        {
-            from_group = message_data["from_group"].asInteger();
-        }
-        else
-        {
-            from_group = message_data["from_group"].asString() == "Y";
+        // Todo: once drtsim-451 releases, remove the string option
+        BOOL from_group;
+        if (message_data["from_group"].isInteger())
+        {
+            from_group = message_data["from_group"].asInteger();
+        }
+        else
+        {
+            from_group = message_data["from_group"].asString() == "Y";
         }
 
         LLIMProcessing::processNewMessage(
-- 
cgit v1.2.3


From ff2721823fc091b3eccabba2886b90e30d9ec305 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 9 Jul 2020 00:42:44 +0300
Subject: SL-13579 Parcel media cannot be played if Media auto-play is set to
 No.

---
 indra/newview/llviewerparcelaskplay.cpp       |  2 ++
 indra/newview/llviewerparcelmedia.cpp         | 38 +++++++--------------------
 indra/newview/llviewerparcelmediaautoplay.cpp |  4 +--
 indra/newview/llviewerparcelmediaautoplay.h   |  3 ++-
 4 files changed, 16 insertions(+), 31 deletions(-)

diff --git a/indra/newview/llviewerparcelaskplay.cpp b/indra/newview/llviewerparcelaskplay.cpp
index d4aa783f12..74586dadc3 100644
--- a/indra/newview/llviewerparcelaskplay.cpp
+++ b/indra/newview/llviewerparcelaskplay.cpp
@@ -78,6 +78,8 @@ void LLViewerParcelAskPlay::askToPlay(const LLUUID &region_id, const S32 &parcel
     default:
         {
             // create or re-create notification
+            // Note: will create and immediately cancel one notification if region has both media and music
+            // since ask play does not distinguish media from music and media can be used as music
             cancelNotification();
 
             if (LLStartUp::getStartupState() > STATE_PRECACHE)
diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp
index 0cdd447fcd..83b05e6b4d 100644
--- a/indra/newview/llviewerparcelmedia.cpp
+++ b/indra/newview/llviewerparcelmedia.cpp
@@ -52,6 +52,10 @@ mMediaParcelLocalID(0)
 	LLMessageSystem* msg = gMessageSystem;
 	msg->setHandlerFunc("ParcelMediaCommandMessage", parcelMediaCommandMessageHandler );
 	msg->setHandlerFunc("ParcelMediaUpdate", parcelMediaUpdateHandler );
+
+    // LLViewerParcelMediaAutoPlay will regularly check and autoplay media,
+    // might be good idea to just integrate it into LLViewerParcelMedia
+    LLSingleton<LLViewerParcelMediaAutoPlay>::getInstance();
 }
 
 LLViewerParcelMedia::~LLViewerParcelMedia()
@@ -80,11 +84,13 @@ void LLViewerParcelMedia::update(LLParcel* parcel)
 			S32 parcelid = parcel->getLocalID();						
 
 			LLUUID regionid = gAgent.getRegion()->getRegionID();
+			bool location_changed = false;
 			if (parcelid != mMediaParcelLocalID || regionid != mMediaRegionID)
 			{
 				LL_DEBUGS("Media") << "New parcel, parcel id = " << parcelid << ", region id = " << regionid << LL_ENDL;
 				mMediaParcelLocalID = parcelid;
 				mMediaRegionID = regionid;
+				location_changed = true;
 			}
 
 			std::string mediaUrl = std::string ( parcel->getMediaURL () );
@@ -102,7 +108,7 @@ void LLViewerParcelMedia::update(LLParcel* parcel)
 			if(mMediaImpl.isNull())
 
 			{
-				play(parcel);
+				// media will be autoplayed by LLViewerParcelMediaAutoPlay
 				return;
 			}
 
@@ -111,8 +117,9 @@ void LLViewerParcelMedia::update(LLParcel* parcel)
 				|| ( mMediaImpl->getMediaTextureID() != parcel->getMediaID() )
 				|| ( mMediaImpl->getMimeType() != parcel->getMediaType() ))
 			{
-				// Only play if the media types are the same.
-				if(mMediaImpl->getMimeType() == parcel->getMediaType())
+				// Only play if the media types are the same and parcel stays same.
+				if(mMediaImpl->getMimeType() == parcel->getMediaType()
+					&& !location_changed)
 				{
 					play(parcel);
 				}
@@ -128,25 +135,6 @@ void LLViewerParcelMedia::update(LLParcel* parcel)
 			stop();
 		}
 	}
-	/*
-	else
-	{
-		// no audio player, do a first use dialog if there is media here
-		if (parcel)
-		{
-			std::string mediaUrl = std::string ( parcel->getMediaURL () );
-			if (!mediaUrl.empty ())
-			{
-				if (gWarningSettings.getBOOL("QuickTimeInstalled"))
-				{
-					gWarningSettings.setBOOL("QuickTimeInstalled", FALSE);
-
-					LLNotificationsUtil::add("NoQuickTime" );
-				};
-			}
-		}
-	}
-	*/
 }
 
 // static
@@ -159,12 +147,6 @@ void LLViewerParcelMedia::play(LLParcel* parcel)
 	if (!gSavedSettings.getBOOL("AudioStreamingMedia"))
 		return;
 
-	// This test appears all over the code and really should be facotred out into a single 
-	// call that returns true/false (with option ask dialog) but that is outside of scope
-	// for this work so we'll just directly.
-	if (gSavedSettings.getS32("ParcelMediaAutoPlayEnable") == 0 )
-		return;
-
 	std::string media_url = parcel->getMediaURL();
 	std::string media_current_url = parcel->getMediaCurrentURL();
 	std::string mime_type = parcel->getMediaType();
diff --git a/indra/newview/llviewerparcelmediaautoplay.cpp b/indra/newview/llviewerparcelmediaautoplay.cpp
index 36c7d436f6..db8fcb4dc4 100644
--- a/indra/newview/llviewerparcelmediaautoplay.cpp
+++ b/indra/newview/llviewerparcelmediaautoplay.cpp
@@ -143,7 +143,7 @@ BOOL LLViewerParcelMediaAutoPlay::tick()
 								LLViewerParcelAskPlay::getInstance()->askToPlay(this_region->getRegionID(),
 																				this_parcel->getLocalID(),
 																				this_parcel->getMediaURL(),
-																				onStartMusicResponse);
+																				onStartMediaResponse);
 								break;
   							}
   						}
@@ -160,7 +160,7 @@ BOOL LLViewerParcelMediaAutoPlay::tick()
 }
 
 //static
-void LLViewerParcelMediaAutoPlay::onStartMusicResponse(const LLUUID &region_id, const S32 &parcel_id, const std::string &url, const bool &play)
+void LLViewerParcelMediaAutoPlay::onStartMediaResponse(const LLUUID &region_id, const S32 &parcel_id, const std::string &url, const bool &play)
 {
     if (play)
     {
diff --git a/indra/newview/llviewerparcelmediaautoplay.h b/indra/newview/llviewerparcelmediaautoplay.h
index cf8e9a97e7..d71fd4c075 100644
--- a/indra/newview/llviewerparcelmediaautoplay.h
+++ b/indra/newview/llviewerparcelmediaautoplay.h
@@ -39,7 +39,8 @@ public:
 	static void playStarted();
 
  private:
-	static void onStartMusicResponse(const LLUUID &region_id, const S32 &parcel_id, const std::string &url, const bool &play);
+    // for askToPlay
+	static void onStartMediaResponse(const LLUUID &region_id, const S32 &parcel_id, const std::string &url, const bool &play);
 
  private:
 	S32 mLastParcelID;
-- 
cgit v1.2.3


From bbee0658c3a7837e47d171dacfda55cac803e3ed Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Thu, 2 Apr 2020 10:55:31 -0700
Subject: Fixed -Wstring-plus-int related errors for compatibility with
 Xcode-11.4

---
 indra/llcommon/llsdutil.cpp        | 2 +-
 indra/newview/llcommandhandler.cpp | 2 +-
 indra/newview/llxmlrpclistener.cpp | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp
index 6a23c443a0..1f8384f415 100644
--- a/indra/llcommon/llsdutil.cpp
+++ b/indra/llcommon/llsdutil.cpp
@@ -506,7 +506,7 @@ struct Data
     const char* name;
 } typedata[] =
 {
-#define def(type) { LLSD::type, #type + 4 }
+#define def(type) { LLSD::type, &#type[4] }
     def(TypeUndefined),
     def(TypeBoolean),
     def(TypeInteger),
diff --git a/indra/newview/llcommandhandler.cpp b/indra/newview/llcommandhandler.cpp
index 76d965b1f1..23e2271eae 100644
--- a/indra/newview/llcommandhandler.cpp
+++ b/indra/newview/llcommandhandler.cpp
@@ -222,7 +222,7 @@ struct symbol_info
 
 #define ent(SYMBOL)										\
 	{													\
-		#SYMBOL + 28, /* skip "LLCommandHandler::UNTRUSTED_" prefix */	\
+		&#SYMBOL[28], /* skip "LLCommandHandler::UNTRUSTED_" prefix */	\
 		SYMBOL											\
 	}
 
diff --git a/indra/newview/llxmlrpclistener.cpp b/indra/newview/llxmlrpclistener.cpp
index 0693d08dfb..0daf3e761d 100644
--- a/indra/newview/llxmlrpclistener.cpp
+++ b/indra/newview/llxmlrpclistener.cpp
@@ -100,7 +100,7 @@ public:
     {
         // from curl.h
 // skip the "CURLE_" prefix for each of these strings
-#define def(sym) (mMap[sym] = #sym + 6)
+#define def(sym) (mMap[sym] = &#sym[6])
         def(CURLE_OK);
         def(CURLE_UNSUPPORTED_PROTOCOL);    /* 1 */
         def(CURLE_FAILED_INIT);             /* 2 */
-- 
cgit v1.2.3


From 383e250fa6484a160bc733cca981fc4cffc8de88 Mon Sep 17 00:00:00 2001
From: Nicky Dasmijn <nicky.dasmijn@gmail.com>
Date: Sat, 18 Jul 2020 10:27:54 +0200
Subject: Linux needs strcmp , include <string.h> so we get access to that
 function.

---
 indra/llcommon/llstl.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h
index b024b47225..a90c2c7e08 100644
--- a/indra/llcommon/llstl.h
+++ b/indra/llcommon/llstl.h
@@ -36,6 +36,10 @@
 #include <set>
 #include <typeinfo>
 
+#ifdef LL_LINUX
+// <ND> For strcmp
+#include <string.h>
+#endif
 // Use to compare the first element only of a pair
 // e.g. typedef std::set<std::pair<int, Data*>, compare_pair<int, Data*> > some_pair_set_t; 
 template <typename T1, typename T2>
-- 
cgit v1.2.3


From c16a364377fef29454c958087121de103fa9de41 Mon Sep 17 00:00:00 2001
From: Nicky Dasmijn <nicky.dasmijn@gmail.com>
Date: Sat, 18 Jul 2020 10:29:01 +0200
Subject: There was an idiom to test with LL_DARWIN if the compiler used is
 clang. This is not correct, as clang is available on all 3 platforms. The
 correct way to check for this is via __clang__
 (https://clang.llvm.org/docs/LanguageExtensions.html#builtin-macros)

---
 indra/llkdu/include_kdu_xxxx.h           | 2 +-
 indra/llkdu/tests/llimagej2ckdu_test.cpp | 2 +-
 indra/llui/llrngwriter.cpp               | 2 +-
 indra/llui/lluictrlfactory.h             | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/indra/llkdu/include_kdu_xxxx.h b/indra/llkdu/include_kdu_xxxx.h
index a1dbced60b..61204b5689 100644
--- a/indra/llkdu/include_kdu_xxxx.h
+++ b/indra/llkdu/include_kdu_xxxx.h
@@ -16,7 +16,7 @@
 // #include "include_kdu_xxxx.h"
 // // kdu_xxxx #undef'ed by include_kdu_xxxx.h
 
-#if LL_DARWIN
+#if __clang__
 // don't *really* want to rebuild KDU so turn off specific warnings for this header
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wself-assign-field"
diff --git a/indra/llkdu/tests/llimagej2ckdu_test.cpp b/indra/llkdu/tests/llimagej2ckdu_test.cpp
index 79ed566d00..ee7b14be85 100644
--- a/indra/llkdu/tests/llimagej2ckdu_test.cpp
+++ b/indra/llkdu/tests/llimagej2ckdu_test.cpp
@@ -29,7 +29,7 @@
 // Class to test 
 #include "llimagej2ckdu.h"
 
-#if LL_DARWIN
+#if __clang__
 // For this source, it's true that private fields in llkdumem.h are unused.
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wunused-private-field"
diff --git a/indra/llui/llrngwriter.cpp b/indra/llui/llrngwriter.cpp
index e4a31d6a79..80e9842a9b 100644
--- a/indra/llui/llrngwriter.cpp
+++ b/indra/llui/llrngwriter.cpp
@@ -29,7 +29,7 @@
 #include "llrngwriter.h"
 #include "lluicolor.h"
 
-#if LL_DARWIN
+#ifdef __clang__
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdelete-incomplete"
 #include "lluictrlfactory.h"
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index f740f14e4d..0ed7fb09b3 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -174,7 +174,7 @@ public:
 				{
 					LL_WARNS() << "Widget in " << filename << " was of type " << typeid(view).name() << " instead of expected type " << typeid(T).name() << LL_ENDL;
 
-#if LL_DARWIN
+#ifdef __clang__
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdelete-incomplete"
 					delete view;
-- 
cgit v1.2.3


From acaa2723308a3cd5b90c0f337520478f67910804 Mon Sep 17 00:00:00 2001
From: Nicky Dasmijn <nicky.dasmijn@gmail.com>
Date: Sat, 18 Jul 2020 13:55:55 +0200
Subject: LLExtStat had been a S32, this wasn't right, as some of the constants
 lead to integer overflow: const LLExtStat LL_EXSTAT_RES_RESULT = 2L<<30;
 const LLExtStat LL_EXSTAT_VFS_RESULT = 3L<<30; This shifts into the sign bit
 and clang gets (rightfully) upset about this.

LLExtStatus needs to be at least of type U32 to remedy this problem, but
while at it it makes sense to turn it into what it is: An enum. Turning
it into a class enum has the added benefit we get type safety for mostly
free.
Which incidentally turned up a problem right away:
A call to removeAndCallbackPendingDownloads had status and extstatus
reversed and thus was wrong.
---
 indra/llmessage/llassetstorage.cpp        | 30 +++++++++---------
 indra/llmessage/llextendedstatus.h        | 51 +++++++++++++++----------------
 indra/llmessage/lltransfertargetvfile.cpp |  2 +-
 indra/llmessage/llxfer.cpp                |  2 +-
 indra/llmessage/llxfer_mem.cpp            |  2 +-
 indra/newview/llsettingsvo.cpp            |  2 +-
 indra/newview/llviewerassetstorage.cpp    | 24 +++++++--------
 7 files changed, 56 insertions(+), 57 deletions(-)

diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp
index 18b2b124e1..94be56086b 100644
--- a/indra/llmessage/llassetstorage.cpp
+++ b/indra/llmessage/llassetstorage.cpp
@@ -426,11 +426,11 @@ void LLAssetStorage::_cleanupRequests(BOOL all, S32 error)
         LLAssetRequest* tmp = *curiter;
         if (tmp->mUpCallback)
         {
-            tmp->mUpCallback(tmp->getUUID(), tmp->mUserData, error, LL_EXSTAT_NONE);
+            tmp->mUpCallback(tmp->getUUID(), tmp->mUserData, error, LLExtStat::LL_EXSTAT_NONE);
         }
         if (tmp->mDownCallback)
         {
-            tmp->mDownCallback(mVFS, tmp->getUUID(), tmp->getType(), tmp->mUserData, error, LL_EXSTAT_NONE);
+            tmp->mDownCallback(mVFS, tmp->getUUID(), tmp->getType(), tmp->mUserData, error, LLExtStat::LL_EXSTAT_NONE);
         }
         if (tmp->mInfoCallback)
         {
@@ -465,7 +465,7 @@ bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAsse
             // we've already got the file
             if (callback)
             {
-                callback(mStaticVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
+                callback(mStaticVFS, uuid, type, user_data, LL_ERR_NOERR, LLExtStat::LL_EXSTAT_VFS_CACHED);
             }
             return true;
         }
@@ -506,7 +506,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid,
         if (callback)
         {
             add(sFailedDownloadCount, 1);
-            callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_NONE);
+            callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LLExtStat::LL_EXSTAT_NONE);
         }
         return;
     }
@@ -517,7 +517,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid,
         if (callback)
         {
             add(sFailedDownloadCount, 1);
-            callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID);
+            callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LLExtStat::LL_EXSTAT_NULL_UUID);
         }
         return;
     }
@@ -540,7 +540,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid,
         // unless there's a weird error
         if (callback)
         {
-            callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
+            callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LLExtStat::LL_EXSTAT_VFS_CACHED);
         }
 
         LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in VFS" << LL_ENDL;
@@ -694,7 +694,7 @@ void LLAssetStorage::downloadCompleteCallback(
         }
     }
 
-    removeAndCallbackPendingDownloads(file_id, file_type, callback_id, callback_type, ext_status, result);
+    removeAndCallbackPendingDownloads(file_id, file_type, callback_id, callback_type, result, ext_status);
 }
 
 void LLAssetStorage::getEstateAsset(
@@ -719,7 +719,7 @@ void LLAssetStorage::getEstateAsset(
         if (callback)
         {
             add(sFailedDownloadCount, 1);
-            callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID);
+            callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LLExtStat::LL_EXSTAT_NULL_UUID);
         }
         return;
     }
@@ -741,7 +741,7 @@ void LLAssetStorage::getEstateAsset(
         // unless there's a weird error
         if (callback)
         {
-            callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
+            callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LLExtStat::LL_EXSTAT_VFS_CACHED);
         }
     }
     else
@@ -792,7 +792,7 @@ void LLAssetStorage::getEstateAsset(
             if (callback)
             {
                 add(sFailedDownloadCount, 1);
-                callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
+                callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LLExtStat::LL_EXSTAT_NO_UPSTREAM);
             }
         }
     }
@@ -885,7 +885,7 @@ void LLAssetStorage::getInvItemAsset(
         // unless there's a weird error
         if (callback)
         {
-            callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
+            callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LLExtStat::LL_EXSTAT_VFS_CACHED);
         }
     }
     else
@@ -936,7 +936,7 @@ void LLAssetStorage::getInvItemAsset(
             if (callback)
             {
                 add(sFailedDownloadCount, 1);
-                callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
+                callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LLExtStat::LL_EXSTAT_NO_UPSTREAM);
             }
         }
     }
@@ -1034,7 +1034,7 @@ void LLAssetStorage::processUploadComplete(LLMessageSystem *msg, void **user_dat
     msg->getBOOLFast(_PREHASH_AssetBlock, _PREHASH_Success, success);
 
     asset_type = (LLAssetType::EType)asset_type_s8;
-    this_ptr->_callUploadCallbacks(uuid, asset_type, success, LL_EXSTAT_NONE);
+    this_ptr->_callUploadCallbacks(uuid, asset_type, success, LLExtStat::LL_EXSTAT_NONE);
 }
 
 void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType asset_type, BOOL success, LLExtStat ext_status )
@@ -1288,12 +1288,12 @@ bool LLAssetStorage::deletePendingRequestImpl(LLAssetStorage::request_list_t* re
         // Run callbacks.
         if (req->mUpCallback)
         {
-            req->mUpCallback(req->getUUID(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED);
+            req->mUpCallback(req->getUUID(), req->mUserData, error, LLExtStat::LL_EXSTAT_REQUEST_DROPPED);
         }
         if (req->mDownCallback)
         {
             add(sFailedDownloadCount, 1);
-            req->mDownCallback(mVFS, req->getUUID(), req->getType(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED);
+            req->mDownCallback(mVFS, req->getUUID(), req->getType(), req->mUserData, error, LLExtStat::LL_EXSTAT_REQUEST_DROPPED);
         }
         if (req->mInfoCallback)
         {
diff --git a/indra/llmessage/llextendedstatus.h b/indra/llmessage/llextendedstatus.h
index 8ce173d1ff..8bb8165419 100644
--- a/indra/llmessage/llextendedstatus.h
+++ b/indra/llmessage/llextendedstatus.h
@@ -28,40 +28,39 @@
 #ifndef LL_LLEXTENDEDSTATUS_H
 #define LL_LLEXTENDEDSTATUS_H
 
+enum class LLExtStat: uint32_t
+{
+	// Status provider groups - Top bits indicate which status type it is
+	// Zero is common status code (next section)
+	LL_EXSTAT_CURL_RESULT	= 1UL<<30, // serviced by curl - use 1L if we really implement the below
+	LL_EXSTAT_RES_RESULT	= 2UL<<30, // serviced by resident copy
+	LL_EXSTAT_VFS_RESULT	= 3UL<<30, // serviced by vfs
 
-typedef S32 LLExtStat;
 
+	// Common Status Codes
+	//
+	LL_EXSTAT_NONE				= 0x00000, // No extra info here - sorry!
+	LL_EXSTAT_NULL_UUID			= 0x10001, // null asset ID
+	LL_EXSTAT_NO_UPSTREAM		= 0x10002, // attempt to upload without a valid upstream method/provider
+	LL_EXSTAT_REQUEST_DROPPED	= 0x10003, // request was dropped unserviced
+	LL_EXSTAT_NONEXISTENT_FILE	= 0x10004, // trying to upload a file that doesn't exist
+	LL_EXSTAT_BLOCKED_FILE		= 0x10005, // trying to upload a file that we can't open
 
-// Status provider groups - Top bits indicate which status type it is
-// Zero is common status code (next section)
-const LLExtStat LL_EXSTAT_CURL_RESULT	= 1L<<30; // serviced by curl - use 1L if we really implement the below
-const LLExtStat LL_EXSTAT_RES_RESULT	= 2L<<30; // serviced by resident copy
-const LLExtStat LL_EXSTAT_VFS_RESULT	= 3L<<30; // serviced by vfs
 
+	// curl status codes:
+	//
+	// Mask off LL_EXSTAT_CURL_RESULT for original result and
+	// see: libraries/include/curl/curl.h
 
-// Common Status Codes
-//
-const LLExtStat LL_EXSTAT_NONE				= 0x00000; // No extra info here - sorry!
-const LLExtStat LL_EXSTAT_NULL_UUID			= 0x10001; // null asset ID
-const LLExtStat LL_EXSTAT_NO_UPSTREAM		= 0x10002; // attempt to upload without a valid upstream method/provider
-const LLExtStat LL_EXSTAT_REQUEST_DROPPED	= 0x10003; // request was dropped unserviced
-const LLExtStat LL_EXSTAT_NONEXISTENT_FILE	= 0x10004; // trying to upload a file that doesn't exist
-const LLExtStat LL_EXSTAT_BLOCKED_FILE		= 0x10005; // trying to upload a file that we can't open
 
+	// Memory-Resident status codes:
+	// None at present
 
-// curl status codes:
-//
-// Mask off LL_EXSTAT_CURL_RESULT for original result and
-// see: libraries/include/curl/curl.h
 
-
-// Memory-Resident status codes:
-// None at present
-
-
-// VFS status codes:
-const LLExtStat LL_EXSTAT_VFS_CACHED	= LL_EXSTAT_VFS_RESULT | 0x0001;
-const LLExtStat LL_EXSTAT_VFS_CORRUPT	= LL_EXSTAT_VFS_RESULT | 0x0002;
+	// VFS status codes:
+	LL_EXSTAT_VFS_CACHED	= LL_EXSTAT_VFS_RESULT | 0x0001,
+	LL_EXSTAT_VFS_CORRUPT	= LL_EXSTAT_VFS_RESULT | 0x0002,
+};
 
 
 #endif // LL_LLEXTENDEDSTATUS_H
diff --git a/indra/llmessage/lltransfertargetvfile.cpp b/indra/llmessage/lltransfertargetvfile.cpp
index a572c68a7f..6fc971cc69 100644
--- a/indra/llmessage/lltransfertargetvfile.cpp
+++ b/indra/llmessage/lltransfertargetvfile.cpp
@@ -227,7 +227,7 @@ void LLTransferTargetVFile::completionCallback(const LLTSCode status)
                 mParams.getAssetID(),
                 mParams.getAssetType(),
                 mParams.mRequestDatap,
-                LL_EXSTAT_NONE);
+				LLExtStat::LL_EXSTAT_NONE);
         }
         delete mParams.mRequestDatap;
         mParams.mRequestDatap = NULL;
diff --git a/indra/llmessage/llxfer.cpp b/indra/llmessage/llxfer.cpp
index 32e0e2cc3b..fcd77b93a8 100644
--- a/indra/llmessage/llxfer.cpp
+++ b/indra/llmessage/llxfer.cpp
@@ -319,7 +319,7 @@ S32 LLXfer::processEOF()
 
 	if (mCallback)
 	{
-		mCallback(mCallbackDataHandle,mCallbackResult,LL_EXSTAT_NONE);
+		mCallback(mCallbackDataHandle,mCallbackResult, LLExtStat::LL_EXSTAT_NONE);
 	}
 
 	return(retval);
diff --git a/indra/llmessage/llxfer_mem.cpp b/indra/llmessage/llxfer_mem.cpp
index 78a3e4f558..7bd78b7c75 100644
--- a/indra/llmessage/llxfer_mem.cpp
+++ b/indra/llmessage/llxfer_mem.cpp
@@ -112,7 +112,7 @@ S32 LLXfer_Mem::processEOF()
 
 	if (mCallback)
 	{
-		mCallback((void *)mBuffer,mBufferLength,mCallbackDataHandle,mCallbackResult,LL_EXSTAT_NONE);
+		mCallback((void *)mBuffer,mBufferLength,mCallbackDataHandle,mCallbackResult, LLExtStat::LL_EXSTAT_NONE);
 	}
 
 	return(retval);
diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp
index c72a0706cd..97b5b2a57d 100644
--- a/indra/newview/llsettingsvo.cpp
+++ b/indra/newview/llsettingsvo.cpp
@@ -329,7 +329,7 @@ void LLSettingsVOBase::onAssetDownloadComplete(LLVFS *vfs, const LLUUID &asset_i
     }
     else
     {
-        LL_WARNS("SETTINGS") << "Error retrieving asset " << asset_id << ". Status code=" << status << "(" << LLAssetStorage::getErrorString(status) << ") ext_status=" << ext_status << LL_ENDL;
+        LL_WARNS("SETTINGS") << "Error retrieving asset " << asset_id << ". Status code=" << status << "(" << LLAssetStorage::getErrorString(status) << ") ext_status=" << (U32)ext_status << LL_ENDL;
     }
     if (callback)
         callback(asset_id, settings, status, ext_status);
diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp
index e0b64403ef..26bea20689 100644
--- a/indra/newview/llviewerassetstorage.cpp
+++ b/indra/newview/llviewerassetstorage.cpp
@@ -168,7 +168,7 @@ void LLViewerAssetStorage::storeAssetData(
                 delete req;
                 if (callback)
                 {
-                    callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_VFS_CORRUPT);
+                    callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_FAILED, LLExtStat::LL_EXSTAT_VFS_CORRUPT);
                 }
                 return;
             }
@@ -209,7 +209,7 @@ void LLViewerAssetStorage::storeAssetData(
 
                     if (callback)
                     {
-                        callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_VFS_CORRUPT);
+                        callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LLExtStat::LL_EXSTAT_VFS_CORRUPT);
                     }
                     return;
                 }
@@ -236,7 +236,7 @@ void LLViewerAssetStorage::storeAssetData(
             reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" );
             if (callback)
             {
-                callback(asset_id, user_data,  LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_NONEXISTENT_FILE);
+                callback(asset_id, user_data,  LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LLExtStat::LL_EXSTAT_NONEXISTENT_FILE);
             }
         }
     }
@@ -247,7 +247,7 @@ void LLViewerAssetStorage::storeAssetData(
         reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_NO_UPSTREAM, __FILE__, __LINE__, "No upstream provider" );
         if (callback)
         {
-            callback(asset_id, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
+            callback(asset_id, user_data, LL_ERR_CIRCUIT_GONE, LLExtStat::LL_EXSTAT_NO_UPSTREAM);
         }
     }
 }
@@ -333,7 +333,7 @@ void LLViewerAssetStorage::storeAssetData(
         }
         if (callback)
         {
-            callback(asset_id, user_data, LL_ERR_CANNOT_OPEN_FILE, LL_EXSTAT_BLOCKED_FILE);
+            callback(asset_id, user_data, LL_ERR_CANNOT_OPEN_FILE, LLExtStat::LL_EXSTAT_BLOCKED_FILE);
         }
     }
 }
@@ -444,13 +444,13 @@ void LLViewerAssetStorage::assetRequestCoro(
     mCountStarted++;
     
     S32 result_code = LL_ERR_NOERR;
-    LLExtStat ext_status = LL_EXSTAT_NONE;
+    LLExtStat ext_status = LLExtStat::LL_EXSTAT_NONE;
 
     if (!gAgent.getRegion())
     {
         LL_WARNS_ONCE("ViewerAsset") << "Asset request fails: no region set" << LL_ENDL;
         result_code = LL_ERR_ASSET_REQUEST_FAILED;
-        ext_status = LL_EXSTAT_NONE;
+        ext_status = LLExtStat::LL_EXSTAT_NONE;
         removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status);
 		return;
     }
@@ -475,7 +475,7 @@ void LLViewerAssetStorage::assetRequestCoro(
     {
         LL_WARNS_ONCE("ViewerAsset") << "asset request fails: caps received but no viewer asset cap found" << LL_ENDL;
         result_code = LL_ERR_ASSET_REQUEST_FAILED;
-        ext_status = LL_EXSTAT_NONE;
+        ext_status = LLExtStat::LL_EXSTAT_NONE;
         removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status);
 		return;
     }
@@ -504,7 +504,7 @@ void LLViewerAssetStorage::assetRequestCoro(
     {
         LL_DEBUGS("ViewerAsset") << "request failed, status " << status.toTerseString() << LL_ENDL;
         result_code = LL_ERR_ASSET_REQUEST_FAILED;
-        ext_status = LL_EXSTAT_NONE;
+        ext_status = LLExtStat::LL_EXSTAT_NONE;
     }
     else
     {
@@ -530,13 +530,13 @@ void LLViewerAssetStorage::assetRequestCoro(
                 // TODO asset-http: handle error
                 LL_WARNS("ViewerAsset") << "Failure in vf.write()" << LL_ENDL;
                 result_code = LL_ERR_ASSET_REQUEST_FAILED;
-                ext_status = LL_EXSTAT_VFS_CORRUPT;
+                ext_status = LLExtStat::LL_EXSTAT_VFS_CORRUPT;
             }
             else if (!vf.rename(uuid, atype))
             {
                 LL_WARNS("ViewerAsset") << "rename failed" << LL_ENDL;
                 result_code = LL_ERR_ASSET_REQUEST_FAILED;
-                ext_status = LL_EXSTAT_VFS_CORRUPT;
+                ext_status = LLExtStat::LL_EXSTAT_VFS_CORRUPT;
             }
             else
             {
@@ -548,7 +548,7 @@ void LLViewerAssetStorage::assetRequestCoro(
             // TODO asset-http: handle invalid size case
 			LL_WARNS("ViewerAsset") << "bad size" << LL_ENDL;
             result_code = LL_ERR_ASSET_REQUEST_FAILED;
-            ext_status = LL_EXSTAT_NONE;
+            ext_status = LLExtStat::LL_EXSTAT_NONE;
         }
     }
 
-- 
cgit v1.2.3


From 7d5a4d71acb1ff751dbdf4163063ab75687888ae Mon Sep 17 00:00:00 2001
From: Nicky Dasmijn <nicky.dasmijn@gmail.com>
Date: Mon, 20 Jul 2020 19:44:05 +0200
Subject: Put hash for boost namespace properly into that by using namespace
 boost

---
 indra/llcommon/llsdutil.h | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h
index 84be95ba54..8678ca97f2 100644
--- a/indra/llcommon/llsdutil.h
+++ b/indra/llcommon/llsdutil.h
@@ -558,9 +558,11 @@ LLSD shallow(LLSD value, LLSD filter=LLSD()) { return llsd_shallow(value, filter
 
 } // namespace llsd
 
-// Specialization for generating a hash value from an LLSD block. 
+// Specialization for generating a hash value from an LLSD block.
+namespace boost
+{
 template <>
-struct boost::hash<LLSD>
+struct hash<LLSD>
 {
     typedef LLSD argument_type;
     typedef std::size_t result_type;
@@ -621,5 +623,5 @@ struct boost::hash<LLSD>
         return seed;
     }
 };
-
+}
 #endif // LL_LLSDUTIL_H
-- 
cgit v1.2.3


From fba9abbb193c89c2c026745ca153a4a8206f3973 Mon Sep 17 00:00:00 2001
From: Nicky Dasmijn <nicky.dasmijn@gmail.com>
Date: Tue, 21 Jul 2020 16:09:34 +0200
Subject: Remove redundant LL_EXSTAT_ from enums.

---
 indra/llmessage/llassetstorage.cpp        | 28 ++++++++++++++--------------
 indra/llmessage/llextendedstatus.h        | 27 ++++++++++++---------------
 indra/llmessage/lltransfertargetvfile.cpp |  2 +-
 indra/llmessage/llxfer.cpp                |  2 +-
 indra/llmessage/llxfer_mem.cpp            |  2 +-
 indra/newview/llviewerassetstorage.cpp    | 24 ++++++++++++------------
 6 files changed, 41 insertions(+), 44 deletions(-)

diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp
index 94be56086b..d7801b6ddc 100644
--- a/indra/llmessage/llassetstorage.cpp
+++ b/indra/llmessage/llassetstorage.cpp
@@ -426,11 +426,11 @@ void LLAssetStorage::_cleanupRequests(BOOL all, S32 error)
         LLAssetRequest* tmp = *curiter;
         if (tmp->mUpCallback)
         {
-            tmp->mUpCallback(tmp->getUUID(), tmp->mUserData, error, LLExtStat::LL_EXSTAT_NONE);
+            tmp->mUpCallback(tmp->getUUID(), tmp->mUserData, error, LLExtStat::NONE);
         }
         if (tmp->mDownCallback)
         {
-            tmp->mDownCallback(mVFS, tmp->getUUID(), tmp->getType(), tmp->mUserData, error, LLExtStat::LL_EXSTAT_NONE);
+            tmp->mDownCallback(mVFS, tmp->getUUID(), tmp->getType(), tmp->mUserData, error, LLExtStat::NONE);
         }
         if (tmp->mInfoCallback)
         {
@@ -465,7 +465,7 @@ bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAsse
             // we've already got the file
             if (callback)
             {
-                callback(mStaticVFS, uuid, type, user_data, LL_ERR_NOERR, LLExtStat::LL_EXSTAT_VFS_CACHED);
+                callback(mStaticVFS, uuid, type, user_data, LL_ERR_NOERR, LLExtStat::VFS_CACHED);
             }
             return true;
         }
@@ -506,7 +506,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid,
         if (callback)
         {
             add(sFailedDownloadCount, 1);
-            callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LLExtStat::LL_EXSTAT_NONE);
+            callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LLExtStat::NONE);
         }
         return;
     }
@@ -517,7 +517,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid,
         if (callback)
         {
             add(sFailedDownloadCount, 1);
-            callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LLExtStat::LL_EXSTAT_NULL_UUID);
+            callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LLExtStat::NULL_UUID);
         }
         return;
     }
@@ -540,7 +540,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid,
         // unless there's a weird error
         if (callback)
         {
-            callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LLExtStat::LL_EXSTAT_VFS_CACHED);
+            callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LLExtStat::VFS_CACHED);
         }
 
         LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in VFS" << LL_ENDL;
@@ -719,7 +719,7 @@ void LLAssetStorage::getEstateAsset(
         if (callback)
         {
             add(sFailedDownloadCount, 1);
-            callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LLExtStat::LL_EXSTAT_NULL_UUID);
+            callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LLExtStat::NULL_UUID);
         }
         return;
     }
@@ -741,7 +741,7 @@ void LLAssetStorage::getEstateAsset(
         // unless there's a weird error
         if (callback)
         {
-            callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LLExtStat::LL_EXSTAT_VFS_CACHED);
+            callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LLExtStat::VFS_CACHED);
         }
     }
     else
@@ -792,7 +792,7 @@ void LLAssetStorage::getEstateAsset(
             if (callback)
             {
                 add(sFailedDownloadCount, 1);
-                callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LLExtStat::LL_EXSTAT_NO_UPSTREAM);
+                callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LLExtStat::NO_UPSTREAM);
             }
         }
     }
@@ -885,7 +885,7 @@ void LLAssetStorage::getInvItemAsset(
         // unless there's a weird error
         if (callback)
         {
-            callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LLExtStat::LL_EXSTAT_VFS_CACHED);
+            callback(mVFS, asset_id, atype, user_data, LL_ERR_NOERR, LLExtStat::VFS_CACHED);
         }
     }
     else
@@ -936,7 +936,7 @@ void LLAssetStorage::getInvItemAsset(
             if (callback)
             {
                 add(sFailedDownloadCount, 1);
-                callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LLExtStat::LL_EXSTAT_NO_UPSTREAM);
+                callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LLExtStat::NO_UPSTREAM);
             }
         }
     }
@@ -1034,7 +1034,7 @@ void LLAssetStorage::processUploadComplete(LLMessageSystem *msg, void **user_dat
     msg->getBOOLFast(_PREHASH_AssetBlock, _PREHASH_Success, success);
 
     asset_type = (LLAssetType::EType)asset_type_s8;
-    this_ptr->_callUploadCallbacks(uuid, asset_type, success, LLExtStat::LL_EXSTAT_NONE);
+    this_ptr->_callUploadCallbacks(uuid, asset_type, success, LLExtStat::NONE);
 }
 
 void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType asset_type, BOOL success, LLExtStat ext_status )
@@ -1288,12 +1288,12 @@ bool LLAssetStorage::deletePendingRequestImpl(LLAssetStorage::request_list_t* re
         // Run callbacks.
         if (req->mUpCallback)
         {
-            req->mUpCallback(req->getUUID(), req->mUserData, error, LLExtStat::LL_EXSTAT_REQUEST_DROPPED);
+            req->mUpCallback(req->getUUID(), req->mUserData, error, LLExtStat::REQUEST_DROPPED);
         }
         if (req->mDownCallback)
         {
             add(sFailedDownloadCount, 1);
-            req->mDownCallback(mVFS, req->getUUID(), req->getType(), req->mUserData, error, LLExtStat::LL_EXSTAT_REQUEST_DROPPED);
+            req->mDownCallback(mVFS, req->getUUID(), req->getType(), req->mUserData, error, LLExtStat::REQUEST_DROPPED);
         }
         if (req->mInfoCallback)
         {
diff --git a/indra/llmessage/llextendedstatus.h b/indra/llmessage/llextendedstatus.h
index 8bb8165419..9923d73c1a 100644
--- a/indra/llmessage/llextendedstatus.h
+++ b/indra/llmessage/llextendedstatus.h
@@ -32,34 +32,31 @@ enum class LLExtStat: uint32_t
 {
 	// Status provider groups - Top bits indicate which status type it is
 	// Zero is common status code (next section)
-	LL_EXSTAT_CURL_RESULT	= 1UL<<30, // serviced by curl - use 1L if we really implement the below
-	LL_EXSTAT_RES_RESULT	= 2UL<<30, // serviced by resident copy
-	LL_EXSTAT_VFS_RESULT	= 3UL<<30, // serviced by vfs
+	CURL_RESULT	= 1UL<<30, // serviced by curl - use 1L if we really implement the below
+	RES_RESULT	= 2UL<<30, // serviced by resident copy
+	VFS_RESULT	= 3UL<<30, // serviced by vfs
 
 
 	// Common Status Codes
 	//
-	LL_EXSTAT_NONE				= 0x00000, // No extra info here - sorry!
-	LL_EXSTAT_NULL_UUID			= 0x10001, // null asset ID
-	LL_EXSTAT_NO_UPSTREAM		= 0x10002, // attempt to upload without a valid upstream method/provider
-	LL_EXSTAT_REQUEST_DROPPED	= 0x10003, // request was dropped unserviced
-	LL_EXSTAT_NONEXISTENT_FILE	= 0x10004, // trying to upload a file that doesn't exist
-	LL_EXSTAT_BLOCKED_FILE		= 0x10005, // trying to upload a file that we can't open
-
+	NONE			= 0x00000, // No extra info here - sorry!
+	NULL_UUID		= 0x10001, // null asset ID
+	NO_UPSTREAM		= 0x10002, // attempt to upload without a valid upstream method/provider
+	REQUEST_DROPPED	= 0x10003, // request was dropped unserviced
+	NONEXISTENT_FILE= 0x10004, // trying to upload a file that doesn't exist
+	BLOCKED_FILE	= 0x10005, // trying to upload a file that we can't open
 
 	// curl status codes:
 	//
-	// Mask off LL_EXSTAT_CURL_RESULT for original result and
+	// Mask off CURL_RESULT for original result and
 	// see: libraries/include/curl/curl.h
 
-
 	// Memory-Resident status codes:
 	// None at present
 
-
 	// VFS status codes:
-	LL_EXSTAT_VFS_CACHED	= LL_EXSTAT_VFS_RESULT | 0x0001,
-	LL_EXSTAT_VFS_CORRUPT	= LL_EXSTAT_VFS_RESULT | 0x0002,
+	VFS_CACHED	= VFS_RESULT | 0x0001,
+	VFS_CORRUPT	= VFS_RESULT | 0x0002,
 };
 
 
diff --git a/indra/llmessage/lltransfertargetvfile.cpp b/indra/llmessage/lltransfertargetvfile.cpp
index 6fc971cc69..b27f0881e0 100644
--- a/indra/llmessage/lltransfertargetvfile.cpp
+++ b/indra/llmessage/lltransfertargetvfile.cpp
@@ -227,7 +227,7 @@ void LLTransferTargetVFile::completionCallback(const LLTSCode status)
                 mParams.getAssetID(),
                 mParams.getAssetType(),
                 mParams.mRequestDatap,
-				LLExtStat::LL_EXSTAT_NONE);
+				LLExtStat::NONE);
         }
         delete mParams.mRequestDatap;
         mParams.mRequestDatap = NULL;
diff --git a/indra/llmessage/llxfer.cpp b/indra/llmessage/llxfer.cpp
index fcd77b93a8..93d5cfc131 100644
--- a/indra/llmessage/llxfer.cpp
+++ b/indra/llmessage/llxfer.cpp
@@ -319,7 +319,7 @@ S32 LLXfer::processEOF()
 
 	if (mCallback)
 	{
-		mCallback(mCallbackDataHandle,mCallbackResult, LLExtStat::LL_EXSTAT_NONE);
+		mCallback(mCallbackDataHandle,mCallbackResult, LLExtStat::NONE);
 	}
 
 	return(retval);
diff --git a/indra/llmessage/llxfer_mem.cpp b/indra/llmessage/llxfer_mem.cpp
index 7bd78b7c75..da8534ecdc 100644
--- a/indra/llmessage/llxfer_mem.cpp
+++ b/indra/llmessage/llxfer_mem.cpp
@@ -112,7 +112,7 @@ S32 LLXfer_Mem::processEOF()
 
 	if (mCallback)
 	{
-		mCallback((void *)mBuffer,mBufferLength,mCallbackDataHandle,mCallbackResult, LLExtStat::LL_EXSTAT_NONE);
+		mCallback((void *)mBuffer,mBufferLength,mCallbackDataHandle,mCallbackResult, LLExtStat::NONE);
 	}
 
 	return(retval);
diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp
index 26bea20689..c1cee2ffef 100644
--- a/indra/newview/llviewerassetstorage.cpp
+++ b/indra/newview/llviewerassetstorage.cpp
@@ -168,7 +168,7 @@ void LLViewerAssetStorage::storeAssetData(
                 delete req;
                 if (callback)
                 {
-                    callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_FAILED, LLExtStat::LL_EXSTAT_VFS_CORRUPT);
+                    callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_FAILED, LLExtStat::VFS_CORRUPT);
                 }
                 return;
             }
@@ -209,7 +209,7 @@ void LLViewerAssetStorage::storeAssetData(
 
                     if (callback)
                     {
-                        callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LLExtStat::LL_EXSTAT_VFS_CORRUPT);
+                        callback(asset_id, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LLExtStat::VFS_CORRUPT);
                     }
                     return;
                 }
@@ -236,7 +236,7 @@ void LLViewerAssetStorage::storeAssetData(
             reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" );
             if (callback)
             {
-                callback(asset_id, user_data,  LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LLExtStat::LL_EXSTAT_NONEXISTENT_FILE);
+                callback(asset_id, user_data,  LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LLExtStat::NONEXISTENT_FILE);
             }
         }
     }
@@ -247,7 +247,7 @@ void LLViewerAssetStorage::storeAssetData(
         reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_NO_UPSTREAM, __FILE__, __LINE__, "No upstream provider" );
         if (callback)
         {
-            callback(asset_id, user_data, LL_ERR_CIRCUIT_GONE, LLExtStat::LL_EXSTAT_NO_UPSTREAM);
+            callback(asset_id, user_data, LL_ERR_CIRCUIT_GONE, LLExtStat::NO_UPSTREAM);
         }
     }
 }
@@ -333,7 +333,7 @@ void LLViewerAssetStorage::storeAssetData(
         }
         if (callback)
         {
-            callback(asset_id, user_data, LL_ERR_CANNOT_OPEN_FILE, LLExtStat::LL_EXSTAT_BLOCKED_FILE);
+            callback(asset_id, user_data, LL_ERR_CANNOT_OPEN_FILE, LLExtStat::BLOCKED_FILE);
         }
     }
 }
@@ -444,13 +444,13 @@ void LLViewerAssetStorage::assetRequestCoro(
     mCountStarted++;
     
     S32 result_code = LL_ERR_NOERR;
-    LLExtStat ext_status = LLExtStat::LL_EXSTAT_NONE;
+    LLExtStat ext_status = LLExtStat::NONE;
 
     if (!gAgent.getRegion())
     {
         LL_WARNS_ONCE("ViewerAsset") << "Asset request fails: no region set" << LL_ENDL;
         result_code = LL_ERR_ASSET_REQUEST_FAILED;
-        ext_status = LLExtStat::LL_EXSTAT_NONE;
+        ext_status = LLExtStat::NONE;
         removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status);
 		return;
     }
@@ -475,7 +475,7 @@ void LLViewerAssetStorage::assetRequestCoro(
     {
         LL_WARNS_ONCE("ViewerAsset") << "asset request fails: caps received but no viewer asset cap found" << LL_ENDL;
         result_code = LL_ERR_ASSET_REQUEST_FAILED;
-        ext_status = LLExtStat::LL_EXSTAT_NONE;
+        ext_status = LLExtStat::NONE;
         removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status);
 		return;
     }
@@ -504,7 +504,7 @@ void LLViewerAssetStorage::assetRequestCoro(
     {
         LL_DEBUGS("ViewerAsset") << "request failed, status " << status.toTerseString() << LL_ENDL;
         result_code = LL_ERR_ASSET_REQUEST_FAILED;
-        ext_status = LLExtStat::LL_EXSTAT_NONE;
+        ext_status = LLExtStat::NONE;
     }
     else
     {
@@ -530,13 +530,13 @@ void LLViewerAssetStorage::assetRequestCoro(
                 // TODO asset-http: handle error
                 LL_WARNS("ViewerAsset") << "Failure in vf.write()" << LL_ENDL;
                 result_code = LL_ERR_ASSET_REQUEST_FAILED;
-                ext_status = LLExtStat::LL_EXSTAT_VFS_CORRUPT;
+                ext_status = LLExtStat::VFS_CORRUPT;
             }
             else if (!vf.rename(uuid, atype))
             {
                 LL_WARNS("ViewerAsset") << "rename failed" << LL_ENDL;
                 result_code = LL_ERR_ASSET_REQUEST_FAILED;
-                ext_status = LLExtStat::LL_EXSTAT_VFS_CORRUPT;
+                ext_status = LLExtStat::VFS_CORRUPT;
             }
             else
             {
@@ -548,7 +548,7 @@ void LLViewerAssetStorage::assetRequestCoro(
             // TODO asset-http: handle invalid size case
 			LL_WARNS("ViewerAsset") << "bad size" << LL_ENDL;
             result_code = LL_ERR_ASSET_REQUEST_FAILED;
-            ext_status = LLExtStat::LL_EXSTAT_NONE;
+            ext_status = LLExtStat::NONE;
         }
     }
 
-- 
cgit v1.2.3


From b17e2aaff1201f93348de44017de107e38e3c2c7 Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Wed, 22 Jul 2020 06:32:02 +0300
Subject: SL-13642 Updated contributions.txt

---
 doc/contributions.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/doc/contributions.txt b/doc/contributions.txt
index 8047c7cbe0..4d8165faf2 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -1087,6 +1087,7 @@ Nicky Dasmijn
 	SL-11061
     SL-11072
 	SL-13141
+	SL-13642
 Nicky Perian
 	OPEN-1
 	STORM-1087
-- 
cgit v1.2.3


From 1af3dfc0b329aa9b30c4516feecc045dcd1454d4 Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Wed, 22 Jul 2020 06:50:44 +0300
Subject: SL-13642 Updated nghttp2, curl, googlemock, colladadom and boost

Updated nghttp2 to codeticket version 545354
Updated boost to codeticket version 545361
Updated colladadom to codeticket version 545362
Updated googlemock to codeticket version 545363
Updated curl to codeticket version 545369
---
 autobuild.xml | 68 +++++++++++++++++++++++++++++------------------------------
 1 file changed, 34 insertions(+), 34 deletions(-)

diff --git a/autobuild.xml b/autobuild.xml
index 9aa8bd7e7a..32b10afd41 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -166,9 +166,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>c68630bd937509573df87a41452bc464</string>
+              <string>3cc73623c9a976b4f8346a3837f7a916</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56315/526789/boost-1.72-darwin64-539869.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64088/601256/boost-1.72-darwin64-545361.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -202,9 +202,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>097d04c5b064c4be4bc9edb885509a94</string>
+              <string>7d4b2511976449e9a4ec7be41dc8310f</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56321/526797/boost-1.72-windows-539869.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64092/601270/boost-1.72-windows-545361.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -214,9 +214,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>748c4d47cced7ba2b210eb6d0ed33497</string>
+              <string>4ad8df0700745201cddf6b71d7b0949f</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56320/526777/boost-1.72-windows64-539869.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64091/601265/boost-1.72-windows64-545361.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
@@ -308,9 +308,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>76e70d1f024e089bcd1afa6748d67a62</string>
+              <string>02e6a8207dcdaf243dcb6da19b8c3534</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56409/527191/colladadom-2.3.539922-darwin64-539922.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64099/601302/colladadom-2.3.545362-darwin64-545362.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -344,9 +344,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>3d6ab0e5e08a7f03088232e5676a861e</string>
+              <string>8a02a10fc69c8f504dc5335644db184a</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56415/527297/colladadom-2.3.539922-windows-539922.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64104/601313/colladadom-2.3.545362-windows-545362.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -356,16 +356,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>5a31c4d50a04d255e84903f16597d4ed</string>
+              <string>742180324fca7ab92b6a61a36aab4f9d</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56408/527200/colladadom-2.3.539922-windows64-539922.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64103/601314/colladadom-2.3.545362-windows64-545362.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>2.3.539922</string>
+        <string>2.3.545362</string>
       </map>
       <key>curl</key>
       <map>
@@ -398,9 +398,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>decf3d5bd930e9ac6113cf96c61ff230</string>
+              <string>f5ae57117a6518d11f49ccfbfbe0969d</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56342/526921/curl-7.54.1.539883-darwin64-539883.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64131/601402/curl-7.54.1.545369-darwin64-545369.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -434,11 +434,11 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>ebd24261499e458da253d2bc1d95057a</string>
+              <string>2796ae7b09e730a55ac03f74ed669520</string>
               <key>hash_algorithm</key>
               <string>md5</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56361/526996/curl-7.54.1.539883-windows-539883.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64130/601396/curl-7.54.1.545369-windows-545369.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -448,16 +448,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>9eadfc1885c59ebc750f75adf4c20925</string>
+              <string>a8f96e5cdb8128b23d49ff4c3f2233a4</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56360/526989/curl-7.54.1.539883-windows64-539883.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64129/601382/curl-7.54.1.545369-windows64-545369.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>7.54.1.539883</string>
+        <string>7.54.1.545369</string>
       </map>
       <key>db</key>
       <map>
@@ -1262,9 +1262,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>36e2e30610eb131e3522ef84cc67405d</string>
+              <string>f9831360ced94943ab9dfb3fbf5256d3</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56330/526832/googlemock-1.7.0.539876-darwin64-539876.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64101/601290/googlemock-1.7.0.545363-darwin64-545363.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -1298,9 +1298,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>38a2c655876044efe536a8e685e74a2a</string>
+              <string>8149e46b4f7abb3ac284415cfe1366e1</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56336/526861/googlemock-1.7.0.539876-windows-539876.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64102/601296/googlemock-1.7.0.545363-windows-545363.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -1310,16 +1310,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>ff4fa1fd7a1ed9ffa477c4574ffc16af</string>
+              <string>f3851eba809ead2810d702041569d36d</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/56334/526845/googlemock-1.7.0.539876-windows64-539876.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64100/601284/googlemock-1.7.0.545363-windows64-545363.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
           </map>
         </map>
         <key>version</key>
-        <string>1.7.0.539876</string>
+        <string>1.7.0.545363</string>
       </map>
       <key>gstreamer</key>
       <map>
@@ -2412,9 +2412,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>95b69e37b9b4435698682f4ff702cca5</string>
+              <string>937ce1a2158c0cfff37f5989f5b24aba</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/54855/510169/nghttp2-1.25.0.538985-darwin64-538985.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64066/601156/nghttp2-1.40.0.545354-darwin64-545354.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin64</string>
@@ -2448,9 +2448,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>246dd8445be87c698aa7fa318bcdd7e5</string>
+              <string>138b881bdf37dff4e626e022a50dd11f</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55035/511985/nghttp2-1.25.0.538985-windows-538985.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64069/601181/nghttp2-1.40.0.545354-windows-545354.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -2460,9 +2460,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>f2fd2dbe8704ec63ab433cbe8e03f7c4</string>
+              <string>c23c6480c7cbea60a2bd26e257adc0a7</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55031/511978/nghttp2-1.25.0.538985-windows64-538985.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64068/601177/nghttp2-1.40.0.545354-windows64-545354.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows64</string>
@@ -2471,7 +2471,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
         <key>source_type</key>
         <string>hg</string>
         <key>version</key>
-        <string>1.25.0.538985</string>
+        <string>1.40.0.545354</string>
       </map>
       <key>nvapi</key>
       <map>
-- 
cgit v1.2.3


From cd6f7a4e6f90270c1a2f66afe6317bffb2f73088 Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Wed, 22 Jul 2020 13:37:33 +0300
Subject: Mac buildfix

---
 indra/cmake/Copy3rdPartyLibs.cmake | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index 7f84ec146a..429bda473b 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -160,7 +160,7 @@ elseif(DARWIN)
         libndofdev.dylib
         libnghttp2.dylib
         libnghttp2.14.dylib
-        libnghttp2.14.14.0.dylib
+        libnghttp2.14.19.0.dylib
        )
 
     if (FMODSTUDIO)
-- 
cgit v1.2.3


From 3f48ab1c0560d9a0c9401990aa4c9ddfca826d0b Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Thu, 23 Jul 2020 00:46:20 +0300
Subject: SL-13642 Get rid of that ugly ignore -Wdelete-incomplete

Get rid of that ugly '#pragma clang diagnostic ignored "-Wdelete-incomplete"' by making sure the delete always happens inside llview.cpp, where the type of LLView is known.
---
 indra/llui/llrngwriter.cpp   |  7 -------
 indra/llui/lluictrlfactory.h | 10 ++--------
 indra/llui/llview.cpp        |  5 +++++
 3 files changed, 7 insertions(+), 15 deletions(-)

diff --git a/indra/llui/llrngwriter.cpp b/indra/llui/llrngwriter.cpp
index 80e9842a9b..4bd1561425 100644
--- a/indra/llui/llrngwriter.cpp
+++ b/indra/llui/llrngwriter.cpp
@@ -29,14 +29,7 @@
 #include "llrngwriter.h"
 #include "lluicolor.h"
 
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdelete-incomplete"
 #include "lluictrlfactory.h"
-#pragma clang diagnostic pop
-#else
-#include "lluictrlfactory.h"
-#endif
 
 #include "boost/bind.hpp"
 
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index 0ed7fb09b3..135ed57a4f 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -37,6 +37,7 @@
 #include "llheteromap.h"
 
 class LLView;
+void deleteView(LLView*); // Inside LLView.cpp, avoid having to potentially delete an incomplete type here.
 
 // lookup widget constructor funcs by widget name
 template <typename DERIVED_TYPE>
@@ -174,14 +175,7 @@ public:
 				{
 					LL_WARNS() << "Widget in " << filename << " was of type " << typeid(view).name() << " instead of expected type " << typeid(T).name() << LL_ENDL;
 
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdelete-incomplete"
-					delete view;
-#pragma clang diagnostic pop
-#else
-					delete view;
-#endif
+					deleteView(view);
 					view = NULL;
 				}
 			}
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 593c8b12fc..bd213d594a 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -86,6 +86,11 @@ template class LLView* LLView::getChild<class LLView>(
 
 static LLDefaultChildRegistry::Register<LLView> r("view");
 
+void deleteView(LLView *aView)
+{
+	delete aView;
+}
+
 namespace LLInitParam
 {
 	void TypeValues<LLView::EOrientation>::declareValues()
-- 
cgit v1.2.3


From 24625c789833ac8762fba6ad31ab670d68acf3e8 Mon Sep 17 00:00:00 2001
From: Callum Prentice <callum@gmail.com>
Date: Tue, 28 Jul 2020 11:38:31 -0700
Subject: Nat's suggested improvement to LLThreadSafeQueue that takes account
 of queue being empty as well as the status flag condition

---
 indra/llcommon/llthreadsafequeue.h | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 30dd507f73..26e0d71d31 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -304,14 +304,13 @@ template<typename ElementT>
 bool LLThreadSafeQueue<ElementT>::isClosed()
 {
     lock_t lock(mLock);
-    return mClosed;
+    return mClosed && mStorage.size() == 0;
 }
 
 template<typename ElementT>
 LLThreadSafeQueue<ElementT>::operator bool()
 {
-    lock_t lock(mLock);
-    return ! mClosed;
+    return ! isClosed();
 }
 
 #endif
-- 
cgit v1.2.3


From 370a82b7637e0d71239cee76301b943ea08506e0 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 28 Jul 2020 21:54:56 +0300
Subject: SL-13634 Don't warn about convex decomposition issues if it's a stub

---
 indra/newview/llmeshrepository.cpp | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 1fce158eb4..c5ced425f6 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -876,7 +876,7 @@ LLMeshRepoThread::~LLMeshRepoThread()
 void LLMeshRepoThread::run()
 {
 	LLCDResult res = LLConvexDecomposition::initThread();
-	if (res != LLCD_OK)
+	if (res != LLCD_OK && LLConvexDecomposition::isFunctional())
 	{
 		LL_WARNS(LOG_MESH) << "Convex decomposition unable to be loaded.  Expect severe problems." << LL_ENDL;
 	}
@@ -1142,7 +1142,7 @@ void LLMeshRepoThread::run()
 	}
 
 	res = LLConvexDecomposition::quitThread();
-	if (res != LLCD_OK)
+	if (res != LLCD_OK && LLConvexDecomposition::isFunctional())
 	{
 		LL_WARNS(LOG_MESH) << "Convex decomposition unable to be quit." << LL_ENDL;
 	}
@@ -3470,6 +3470,11 @@ void LLMeshRepository::init()
 	
 	LLConvexDecomposition::getInstance()->initSystem();
 
+    if (!LLConvexDecomposition::isFunctional())
+    {
+        LL_INFOS(LOG_MESH) << "Using STUB for LLConvexDecomposition" << LL_ENDL;
+    }
+
 	mDecompThread = new LLPhysicsDecomp();
 	mDecompThread->start();
 
-- 
cgit v1.2.3


From af7ff3d99f71dfc52fabebf77c985c73f4eb172d Mon Sep 17 00:00:00 2001
From: Andrey Lihatskiy <alihatskiy@productengine.com>
Date: Mon, 3 Aug 2020 13:42:08 +0300
Subject: Updated LLCA to codeticket build 546021

---
 autobuild.xml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/autobuild.xml b/autobuild.xml
index 5d96fdfc50..51515b3696 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -2187,16 +2187,16 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>25db349f18fc1e79f76ab3ba2c8d1330</string>
+              <string>8501cbaa7e0f254614694da784a9c61c</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62723/591962/llca-202007011528.544371-common-544371.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64944/606925/llca-202008010216.546021-common-546021.tar.bz2</string>
             </map>
             <key>name</key>
             <string>common</string>
           </map>
         </map>
         <key>version</key>
-        <string>202007011528.544371</string>
+        <string>202008010216.546021</string>
       </map>
       <key>llphysicsextensions_source</key>
       <map>
-- 
cgit v1.2.3


From bbb16ff97c1dbafa21358dbee8ca686d3c30478e Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 4 Aug 2020 20:36:56 +0300
Subject: SL-13704 Move link generation into getReleaseNotes()

---
 indra/newview/llappviewer.cpp   | 10 +---------
 indra/newview/llversioninfo.cpp | 12 +++++++++++-
 2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index cf9ad7ccbf..379e29a06b 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3101,15 +3101,7 @@ LLSD LLAppViewer::getViewerInfo() const
 
 	// return a URL to the release notes for this viewer, such as:
 	// https://releasenotes.secondlife.com/viewer/2.1.0.123456.html
-	std::string url = versionInfo.getReleaseNotes(); // VVM supplied
-    if (url.empty())
-    {
-        url = LLTrans::getString("RELEASE_NOTES_BASE_URL");
-        if (!LLStringUtil::endsWith(url, "/"))
-            url += "/";
-        url += LLURI::escape(versionInfo.getVersion()) + ".html";
-    }
-	info["VIEWER_RELEASE_NOTES_URL"] = url;
+	info["VIEWER_RELEASE_NOTES_URL"] = versionInfo.getReleaseNotes();;
 
 	// Position
 	LLViewerRegion* region = gAgent.getRegion();
diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp
index 4720a989b0..ccfb9f3e41 100644
--- a/indra/newview/llversioninfo.cpp
+++ b/indra/newview/llversioninfo.cpp
@@ -28,6 +28,7 @@
 #include "llviewerprecompiledheaders.h"
 #include "llevents.h"
 #include "lleventfilter.h"
+#include "lltrans.h"
 #include "llversioninfo.h"
 #include "stringize.h"
 #include <boost/regex.hpp>
@@ -173,5 +174,14 @@ std::string LLVersionInfo::getBuildConfig()
 
 std::string LLVersionInfo::getReleaseNotes()
 {
-    return mReleaseNotes;
+    if (mReleaseNotes.empty())
+    {
+        std::string url = mReleaseNotes;
+        url = LLTrans::getString("RELEASE_NOTES_BASE_URL");
+        if (!LLStringUtil::endsWith(url, "/"))
+            url += "/";
+        url += LLURI::escape(getVersion()) + ".html";
+        return url;
+    }
+    return mReleaseNotes; // VVM supplied
 }
-- 
cgit v1.2.3


From 59b9894d4c88c30432cfb45c1d295d54ba25d42b Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 4 Aug 2020 20:56:18 +0300
Subject: SL-13719 One more exit crash for asset storage

---
 indra/newview/llviewerassetstorage.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp
index 3c61ce15f1..cacdee7e83 100644
--- a/indra/newview/llviewerassetstorage.cpp
+++ b/indra/newview/llviewerassetstorage.cpp
@@ -457,6 +457,11 @@ void LLViewerAssetStorage::assetRequestCoro(
     S32 result_code = LL_ERR_NOERR;
     LLExtStat ext_status = LLExtStat::NONE;
 
+    if (!gAssetStorage)
+    {
+        LL_WARNS_ONCE("ViewerAsset") << "Asset request fails: asset storage no longer exists" << LL_ENDL;
+        return;
+    }
     if (!gAgent.getRegion())
     {
         LL_WARNS_ONCE("ViewerAsset") << "Asset request fails: no region set" << LL_ENDL;
@@ -501,7 +506,7 @@ void LLViewerAssetStorage::assetRequestCoro(
 
     LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts);
 
-    if (LLApp::isQuitting())
+    if (LLApp::isQuitting() || !gAssetStorage)
     {
         // Bail out if result arrives after shutdown has been started.
         return;
-- 
cgit v1.2.3


From 00acc562f929eaa0f89386d97786815e56742d26 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 5 Aug 2020 22:33:57 +0300
Subject: Revert commit bbb16ff97c1dbafa21358dbee8ca686d3c30478e.

This fails at teamcity due to missing LLTrans, but builds locally without issues. Reverting to not hold D501
---
 indra/newview/llappviewer.cpp   | 10 +++++++++-
 indra/newview/llversioninfo.cpp | 12 +-----------
 2 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 379e29a06b..cf9ad7ccbf 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3101,7 +3101,15 @@ LLSD LLAppViewer::getViewerInfo() const
 
 	// return a URL to the release notes for this viewer, such as:
 	// https://releasenotes.secondlife.com/viewer/2.1.0.123456.html
-	info["VIEWER_RELEASE_NOTES_URL"] = versionInfo.getReleaseNotes();;
+	std::string url = versionInfo.getReleaseNotes(); // VVM supplied
+    if (url.empty())
+    {
+        url = LLTrans::getString("RELEASE_NOTES_BASE_URL");
+        if (!LLStringUtil::endsWith(url, "/"))
+            url += "/";
+        url += LLURI::escape(versionInfo.getVersion()) + ".html";
+    }
+	info["VIEWER_RELEASE_NOTES_URL"] = url;
 
 	// Position
 	LLViewerRegion* region = gAgent.getRegion();
diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp
index ccfb9f3e41..4720a989b0 100644
--- a/indra/newview/llversioninfo.cpp
+++ b/indra/newview/llversioninfo.cpp
@@ -28,7 +28,6 @@
 #include "llviewerprecompiledheaders.h"
 #include "llevents.h"
 #include "lleventfilter.h"
-#include "lltrans.h"
 #include "llversioninfo.h"
 #include "stringize.h"
 #include <boost/regex.hpp>
@@ -174,14 +173,5 @@ std::string LLVersionInfo::getBuildConfig()
 
 std::string LLVersionInfo::getReleaseNotes()
 {
-    if (mReleaseNotes.empty())
-    {
-        std::string url = mReleaseNotes;
-        url = LLTrans::getString("RELEASE_NOTES_BASE_URL");
-        if (!LLStringUtil::endsWith(url, "/"))
-            url += "/";
-        url += LLURI::escape(getVersion()) + ".html";
-        return url;
-    }
-    return mReleaseNotes; // VVM supplied
+    return mReleaseNotes;
 }
-- 
cgit v1.2.3


From c27e20703366ceb8a536c0a4ca22645500f426eb Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 6 Aug 2020 17:46:53 +0300
Subject: SL-13737 Crash when cleaning up uninitialized ndof device

---
 indra/newview/llappviewer.cpp      |  7 +++++--
 indra/newview/llviewerjoystick.cpp | 11 +++++++----
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index cf9ad7ccbf..75574df00e 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1851,8 +1851,11 @@ bool LLAppViewer::cleanup()
 	delete gKeyboard;
 	gKeyboard = NULL;
 
-	// Turn off Space Navigator and similar devices
-	LLViewerJoystick::getInstance()->terminate();
+    if (LLViewerJoystick::instanceExists())
+    {
+        // Turn off Space Navigator and similar devices
+        LLViewerJoystick::getInstance()->terminate();
+    }
 
 	LL_INFOS() << "Cleaning up Objects" << LL_ENDL;
 
diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp
index 3d06c95080..491ad7e3b2 100644
--- a/indra/newview/llviewerjoystick.cpp
+++ b/indra/newview/llviewerjoystick.cpp
@@ -309,10 +309,13 @@ void LLViewerJoystick::init(bool autoenable)
 void LLViewerJoystick::terminate()
 {
 #if LIB_NDOF
-
-	ndof_libcleanup();
-	LL_INFOS("joystick") << "Terminated connection with NDOF device." << LL_ENDL;
-	mDriverState = JDS_UNINITIALIZED;
+    if (mNdofDev != NULL)
+    {
+        ndof_libcleanup(); // frees alocated memory in mNdofDev
+        mDriverState = JDS_UNINITIALIZED;
+        mNdofDev = NULL;
+        LL_INFOS("joystick") << "Terminated connection with NDOF device." << LL_ENDL;
+    }
 #endif
 }
 
-- 
cgit v1.2.3


From 1935d25c78bf46f0fdc8758b6f215f53d17fd94a Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 6 Aug 2020 20:05:13 +0300
Subject: Revert "SL-11215: Add release notes URLs to update-related
 notifications."

This reverts commit bf999f2f84dd26844c60d682f563f982a55e8ee8 due to revert of updater, this will be moved to separate 'epic' instead
---
 indra/newview/lllogininstance.cpp                  | 26 ++++------------------
 .../newview/skins/default/xui/en/notifications.xml |  5 -----
 2 files changed, 4 insertions(+), 27 deletions(-)

diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 9d54c8c9c5..0f846c152a 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -332,7 +332,7 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
         {
             data["certificate"] = response["certificate"];
         }
-
+        
         if (gViewerWindow)
             gViewerWindow->setShowProgress(FALSE);
 
@@ -349,31 +349,13 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
         // login.cgi is insisting on a required update. We were called with an
         // event that bundles both the login.cgi 'response' and the
         // synchronization event from the 'updater'.
-        std::string login_version = response["message_args"]["VERSION"];
-        std::string vvm_version   = updater["VERSION"];
-        std::string relnotes      = updater["URL"];
-        LL_WARNS("LLLogin") << "Login failed because an update to version " << login_version << " is required." << LL_ENDL;
-        // vvm_version might be empty because we might not have gotten
-        // SLVersionChecker's LoginSync handshake. But if it IS populated, it
-        // should (!) be the same as the version we got from login.cgi.
-        if ((! vvm_version.empty()) && vvm_version != login_version)
-        {
-            LL_WARNS("LLLogin") << "VVM update version " << vvm_version
-                                << " differs from login version " << login_version
-                                << "; presenting VVM version to match release notes URL"
-                                << LL_ENDL;
-            login_version = vvm_version;
-        }
-        if (relnotes.empty())
-        {
-            // I thought this would be available in strings.xml or some such
-            relnotes = "https://secondlife.com/support/downloads/";
-        }
+        std::string required_version = response["message_args"]["VERSION"];
+        LL_WARNS("LLLogin") << "Login failed because an update to version " << required_version << " is required." << LL_ENDL;
 
         if (gViewerWindow)
             gViewerWindow->setShowProgress(FALSE);
 
-        LLSD args(LLSDMap("VERSION", login_version)("URL", relnotes));
+        LLSD args(LLSDMap("VERSION", required_version));
         if (updater.isUndefined())
         {
             // If the updater failed to shake hands, better advise the user to
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 7e405cf0d0..32ae56e3af 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -4016,8 +4016,6 @@ Finished download of raw terrain file to:
 [DOWNLOAD_PATH].
   </notification>
 
-  <!-- RequiredUpdate does not display release notes URL because we don't get
-       that from login.cgi's login failure message. -->
   <notification
    icon="alertmodal.tga"
    name="RequiredUpdate"
@@ -4035,7 +4033,6 @@ Please download from https://secondlife.com/support/downloads/
    name="PauseForUpdate"
    type="alertmodal">
 Version [VERSION] is required for login.
-Release notes: [URL]
 Click OK to download and install.
     <tag>confirm</tag>
     <usetemplate
@@ -4048,7 +4045,6 @@ Click OK to download and install.
    name="OptionalUpdateReady"
    type="alertmodal">
 Version [VERSION] has been downloaded and is ready to install.
-Release notes: [URL]
 Click OK to install.
     <tag>confirm</tag>
     <usetemplate
@@ -4061,7 +4057,6 @@ Click OK to install.
    name="PromptOptionalUpdate"
    type="alertmodal">
 Version [VERSION] has been downloaded and is ready to install.
-Release notes: [URL]
 Proceed?
     <tag>confirm</tag>
     <usetemplate
-- 
cgit v1.2.3


From 2e66c406d1767f26f968452e9ca5f5c0afa513b2 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 11 Aug 2020 01:20:22 +0300
Subject: SL-13626 Renamed PoolSizeAssetStorage to PoolSizeVAssetStorage

to reflect previous commit and use correct pool size
---
 indra/newview/app_settings/settings.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index dfc3c7b89d..a00aa86d78 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -15161,7 +15161,7 @@
         <key>Value</key>
             <real>1</real>
         </map>
-    <key>PoolSizeAssetStorage</key>
+    <key>PoolSizeVAssetStorage</key>
         <map>
         <key>Comment</key>
             <string>Coroutine Pool size for AssetStorage requests</string>
-- 
cgit v1.2.3


From e8b31d03b4f6f0ffb981b4ea150743daf7b4a958 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Tue, 18 Aug 2020 12:02:30 -0400
Subject: Increment viewer version to 6.4.8 following promotion of DRTVWR-501

---
 indra/newview/VIEWER_VERSION.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 3c43d71599..4b20d9700d 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-6.4.7
+6.4.8
-- 
cgit v1.2.3