From 31e0cefb6c1eabfe931d3b95b585947cce3b21ff 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(-)

(limited to 'indra')

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 5322f41250851e210ad130cbf7b5fa1c04efb6ce 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(-)

(limited to 'indra')

diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 5568a84494..c266bec777 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 1f11f26192..b47b6a5214 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; }
 
@@ -631,7 +638,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 );
@@ -797,7 +804,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 b9294516fc65f7a172ae119e20865b70c43c19c0 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/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 +-
 18 files changed, 268 insertions(+), 53 deletions(-)
 create mode 100644 indra/llcommon/llkeybind.cpp
 create mode 100644 indra/llcommon/llkeybind.h

(limited to 'indra')

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 e7b0e0ef8e..f8c0232660 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 f136918896..e2dac5a1de 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/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 951d11bbe5..95c255d697 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);
@@ -1674,21 +1674,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 526214a617..0bbfdc7c17 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 aeb8bdc496..3879acefa6 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 44d02b4224..822dc20692 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -914,7 +914,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 = "";
@@ -923,6 +923,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))
 	{	
@@ -938,26 +940,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;
 		}
@@ -1075,7 +1077,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)
@@ -1083,8 +1085,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;
 	}
@@ -1098,7 +1099,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);
 }
 
 
@@ -1110,7 +1111,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;
 
@@ -1131,14 +1132,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;
@@ -1293,8 +1293,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;
@@ -1305,12 +1304,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 44c1fbd066..2e1a17596f 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 cc590fc947..3fc41ddacc 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -642,15 +642,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
 	{
@@ -712,7 +712,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 3d04e1f0db..12916ab71b 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -417,7 +417,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 3633ccf1a1077d3e53e7f125d1dd5ed2aaa98906 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

(limited to 'indra')

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 95c255d697..38ec8805a1 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();
 }
 
@@ -2863,6 +2914,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 0bbfdc7c17..bfccd64624 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -294,6 +294,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 77bbcdada6..be8a9a5d2d 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/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index 3fc41ddacc..8951fcf368 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"
 
@@ -691,7 +692,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)
@@ -703,7 +704,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)
@@ -714,7 +715,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 4df05c5a8995158922c7b7aacfef442ac8ae6fdd 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

(limited to 'indra')

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 763c3aeb81..6c30bdde17 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"),
@@ -166,6 +167,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 43e1c0d707..edfbaa6548 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -115,7 +115,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,
@@ -460,6 +461,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 33fa186a2e..340af8ece0 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
     lllegacyatmospherics.cpp
@@ -1007,6 +1008,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 38ec8805a1..34cfe6ebb4 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;
 	}
 	
@@ -1711,53 +1741,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()
@@ -1782,18 +1765,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");
@@ -2794,7 +2765,7 @@ void LLPanelPreferenceGraphics::setPresetText()
 		}
 	}
 
-	if (hasDirtyChilds() && !preset_graphic_active.empty())
+    if (hasDirtyChilds() && !preset_graphic_active.empty())
 	{
 		gSavedSettings.setString("PresetGraphicActive", "");
 		preset_graphic_active.clear();
@@ -2914,98 +2885,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();
@@ -3013,81 +3010,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);
@@ -3095,23 +3082,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()
@@ -3124,61 +3152,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 bfccd64624..c36dee114c 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();
@@ -298,21 +298,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 6914e0fc2b..1c93a2e954 100644
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -605,6 +605,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);
@@ -646,6 +652,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()
@@ -807,7 +814,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;
 }
@@ -818,21 +825,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;
@@ -840,16 +851,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(), 
@@ -857,12 +868,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 8951fcf368..f8588156c1 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"
 
@@ -692,33 +691,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 c60b929fbb615f8d73f7bf42849b5628bf0f8f7a 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(-)

(limited to 'indra')

diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h
index f8c0232660..10b98f49aa 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 f6d6f7c897..f3df79fb6b 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -830,6 +830,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 1a352d3397..88cce0b911 100644
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -351,6 +351,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 ff921dcfdb..1cb3c1af31 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1447,6 +1447,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 34cfe6ebb4..d7a8f9fd4f 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();
 }
@@ -2921,6 +2945,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))
@@ -2932,14 +2973,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);
-                    }
+                    }*/
                 }
             }
         }
@@ -3082,10 +3123,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)
@@ -3175,7 +3212,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;
 
@@ -3190,7 +3228,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 c36dee114c..dbf493b60d 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -311,7 +311,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 1c93a2e954..fb1f33c6b0 100644
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -605,12 +605,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);
@@ -652,20 +690,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++) 
 	{
@@ -673,7 +715,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")
 	{
@@ -707,6 +749,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
@@ -750,7 +826,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;
@@ -791,11 +867,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)
 	{
@@ -809,20 +896,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()
@@ -837,12 +1006,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;
@@ -872,9 +1049,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++;
         }
 	}
@@ -966,7 +1154,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++;
 		}
@@ -978,7 +1166,7 @@ S32 LLViewerKeyboard::loadBindings(const std::string& filename)
 }
 
 
-EKeyboardMode LLViewerKeyboard::getMode()
+EKeyboardMode LLViewerKeyboard::getMode() const
 {
 	if ( gAgentCamera.cameraMouselook() )
 	{
@@ -998,56 +1186,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 822dc20692..af8347688d 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -914,6 +914,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 = "";
@@ -1012,6 +1023,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;
 		}
 
@@ -1058,7 +1074,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;
@@ -1077,7 +1098,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)
@@ -1085,7 +1107,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;
 	}
@@ -1099,46 +1121,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;
@@ -1293,7 +1293,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;
@@ -1304,10 +1304,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;
@@ -1474,7 +1474,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)
@@ -2950,6 +2951,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 2e1a17596f..451a7775cf 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 4ae2165c4516a74012d30610b4c53de6d3ccaf90 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(-)

(limited to 'indra')

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index d7a8f9fd4f..0af6249351 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
 {
@@ -2919,6 +2919,10 @@ LLPanelPreferenceControls::LLPanelPreferenceControls()
     mEditingMode(0),
     mShowKeyDialog(false)
 {
+    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i)
+    {
+        mConflictHandler[i].setLoadMode((LLKeyConflictHandler::EModes)i);
+    }
 }
 
 LLPanelPreferenceControls::~LLPanelPreferenceControls()
@@ -3243,7 +3247,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 3879acefa6..35b4306e1d 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 fb1f33c6b0..abc7346616 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"
@@ -567,7 +568,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);
 
@@ -581,7 +582,8 @@ void start_chat( EKeystate s )
     {
         return; // can't talk, gotta go, kthxbye!
     }
-    
+    if (KEYSTATE_DOWN != s) return;
+
 	// start chat
 	LLFloaterIMNearbyChat::startChat(NULL);
 }
@@ -649,6 +651,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);
@@ -694,6 +709,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()
@@ -756,7 +773,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;
@@ -1045,24 +1062,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++;
         }
 	}
@@ -1261,28 +1298,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)
         {
@@ -1297,10 +1347,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;
+            }
         }
     }
 
@@ -1316,6 +1373,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:
@@ -1360,7 +1418,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 b6c7be2ed3..ab054fabde 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -8031,7 +8031,6 @@ BOOL LLViewerMenuHolderGL::hideMenus()
 	
 	if (LLMenuHolderGL::hideMenus())
 	{
-		LLToolPie::instance().blockClickToWalk();
 		handled = TRUE;
 	}
 
-- 
cgit v1.2.3


From 2532a2ee9ee9003e2c6b72f8da19979a9e3dd2f6 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(-)

(limited to 'indra')

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 e8f01f7a60..d0cd4e2b39 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -8274,7 +8274,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 1cb3c1af31..06deed9e58 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1002,20 +1002,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 0af6249351..4852a9d93e 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();
 }
@@ -2917,11 +2926,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);
     }
 }
 
@@ -2949,46 +2959,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);
 }
@@ -3038,7 +3036,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();
 }
 
@@ -3046,6 +3044,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;
@@ -3138,20 +3142,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())
         {
@@ -3159,11 +3193,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())
         {
@@ -3176,6 +3215,11 @@ void LLPanelPreferenceControls::saveSettings()
     {
         regenerateControls();
     }
+    else if (mHighlightedCell)
+    {
+        mHighlightedCell->setHighlighted(false);
+        mHighlightedCell = NULL;
+    }
 }
 
 void LLPanelPreferenceControls::resetDirtyChilds()
@@ -3209,6 +3253,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()
@@ -3228,30 +3278,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()
@@ -3265,16 +3305,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 dbf493b60d..9178927e74 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;
@@ -314,15 +315,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 35b4306e1d..1b54402221 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 abc7346616..2647abc74c 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
@@ -349,12 +366,13 @@ void camera_spin_around_ccw_sitting( EKeystate s )
 		gAgentCamera.unlockView();
 		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
@@ -366,27 +384,30 @@ void camera_spin_around_cw_sitting( EKeystate s )
 		gAgentCamera.unlockView();
 		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
@@ -397,12 +418,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
@@ -413,26 +435,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);
@@ -441,12 +466,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()))
 	{
@@ -456,139 +482,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 &&
@@ -605,11 +648,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)
     {
@@ -622,11 +666,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();
@@ -635,33 +680,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);
@@ -711,6 +798,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()
@@ -846,7 +935,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;
 
@@ -937,7 +1026,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);
@@ -1107,102 +1196,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() )
@@ -1238,27 +1231,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
@@ -1266,7 +1258,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())
 	{
@@ -1279,17 +1271,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)
@@ -1370,23 +1376,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;
@@ -1403,6 +1416,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;
 }
 
@@ -1415,7 +1452,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 af8347688d..77ae85e7f6 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -934,8 +934,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))
 	{	
@@ -1453,9 +1451,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();
@@ -1480,9 +1475,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 f8588156c1..fca8de7410 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -200,8 +200,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");
 
@@ -637,32 +635,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)
@@ -683,48 +655,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 12916ab71b..cecaac7f85 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -408,16 +408,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 b12cf6696348520556cf70f96e0562776479fe70 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                    | 1463 +++++++++++++++++++
 indra/newview/llviewerinput.h                      |  193 +++
 indra/newview/llviewerkeyboard.cpp                 | 1464 --------------------
 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, 1693 insertions(+), 1697 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

(limited to 'indra')

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 340af8ece0..41f455d63a 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -662,7 +662,7 @@ set(viewer_SOURCE_FILES
     llviewerjointattachment.cpp
     llviewerjointmesh.cpp
     llviewerjoystick.cpp
-    llviewerkeyboard.cpp
+    llviewerinput.cpp
     llviewerlayer.cpp
     llviewermedia.cpp
     llviewermedia_streamingaudio.cpp
@@ -1286,7 +1286,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 06deed9e58..7145f0f29c 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"
@@ -1004,11 +1004,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;
 		}
@@ -1442,7 +1442,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..fb405fd225
--- /dev/null
+++ b/indra/newview/llviewerinput.cpp
@@ -0,0 +1,1463 @@
+/** 
+ * @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.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 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 2647abc74c..0000000000
--- a/indra/newview/llviewerkeyboard.cpp
+++ /dev/null
@@ -1,1464 +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.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 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 77ae85e7f6..28adc2b7ab 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"
@@ -1097,7 +1097,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)
@@ -1105,7 +1105,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;
 	}
@@ -1119,24 +1119,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;
@@ -1291,7 +1291,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;
@@ -1302,10 +1302,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;
@@ -1470,7 +1470,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)
@@ -1482,13 +1482,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
 }
 
@@ -2944,7 +2944,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 9e4297baaf..aa8c79b0d2 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 0b8021870335ff9b9684fb193c6e0fe2f02b4091 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(-)

(limited to 'indra')

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 4852a9d93e..f94a52a232 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 
 
@@ -2921,9 +2986,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),
@@ -2962,8 +3090,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)
@@ -2991,10 +3119,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();
@@ -3006,7 +3134,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))
     {
@@ -3059,76 +3186,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);
         }
     }
 }
@@ -3144,13 +3243,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);
@@ -3207,6 +3306,7 @@ void LLPanelPreferenceControls::saveSettings()
         if (mConflictHandler[i].hasUnsavedChanges())
         {
             mConflictHandler[i].saveToSettings();
+            mConflictHandler[i].clear();
         }
     }
 
@@ -3229,20 +3329,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;
     }
@@ -3251,7 +3352,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)
@@ -3269,18 +3370,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();
@@ -3296,19 +3395,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 9178927e74..e07ead7e18 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -318,7 +318,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();
@@ -328,7 +328,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 fb405fd225..4a06a2012f 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -650,6 +650,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;
@@ -791,6 +863,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 28adc2b7ab..091fc720c1 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -971,6 +971,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 0147a8c989b2bd423077aa8a416298b33bde9dcf 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/llfloateravatarpicker.cpp     | 75 ++---------------------------
 indra/newview/llfloateravatarpicker.h       |  9 +---
 indra/newview/llfloatercolorpicker.cpp      | 11 +----
 indra/newview/llfloatercolorpicker.h        | 11 ++---
 indra/newview/llfloaterexperiencepicker.cpp | 15 ++----
 indra/newview/llfloaterexperiencepicker.h   | 10 +---
 indra/newview/lltexturectrl.cpp             |  2 +-
 indra/newview/lltexturectrl.h               |  6 +--
 9 files changed, 22 insertions(+), 119 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 41f455d63a..340f1f8a22 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
@@ -810,6 +811,7 @@ set(viewer_HEADER_FILES
     lldonotdisturbnotificationstorage.h
     lldndbutton.h
     lldrawable.h
+    lldrawfrustum.h
     lldrawpool.h
     lldrawpoolalpha.h
     lldrawpoolavatar.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 1a784223c2..273dfe72d6 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()
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 c642da7b83..54d27be825 100644
--- a/indra/newview/llfloaterexperiencepicker.cpp
+++ b/indra/newview/llfloaterexperiencepicker.cpp
@@ -64,10 +64,7 @@ LLFloaterExperiencePicker* LLFloaterExperiencePicker::show( select_callback_t ca
 		floater->mSearchPanel->filterContent();
 	}
 
-	if(frustumOrigin)
-	{
-		floater->mFrustumOrigin = frustumOrigin->getHandle();
-	}
+	floater->setFrustumOrigin(frustumOrigin);
 
 	return floater;
 }
@@ -80,21 +77,15 @@ void LLFloaterExperiencePicker::drawFrustum()
 
 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 6a0464c657..7fcc1f4977 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -109,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),
@@ -123,6 +122,7 @@ LLFloaterTexturePicker::LLFloaterTexturePicker(
 	buildFromFile("floater_texture_ctrl.xml");
 	mCanApplyImmediately = can_apply_immediately;
 	setCanMinimize(FALSE);
+	setFrustumOrigin(mOwner);
 }
 
 LLFloaterTexturePicker::~LLFloaterTexturePicker()
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 af7cefe031b0680253c7b0c082216af841a10939 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(-)

(limited to 'indra')

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 6c30bdde17..83f80cfb9e 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),
@@ -165,6 +173,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 edfbaa6548..45ce67349a 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,
@@ -433,7 +447,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);
@@ -458,6 +472,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 04081c0bc882cecb7647648eb035f0f2334bf983 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(-)

(limited to 'indra')

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index f94a52a232..47cc93175e 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");
@@ -3053,9 +3064,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)
     {
@@ -3084,41 +3093,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;
@@ -3170,13 +3144,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;
@@ -3243,6 +3211,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)
@@ -3258,12 +3227,6 @@ void LLPanelPreferenceControls::updateTable()
             cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 2));
         }
     }
-
-    if (mHighlightedCell)
-    {
-        mHighlightedCell->setHighlighted(false);
-        mHighlightedCell = NULL;
-    }
 }
 
 void LLPanelPreferenceControls::apply()
@@ -3275,11 +3238,6 @@ void LLPanelPreferenceControls::apply()
             mConflictHandler[i].saveToSettings();
         }
     }
-    if (mHighlightedCell)
-    {
-        mHighlightedCell->setHighlighted(false);
-        mHighlightedCell = NULL;
-    }
 }
 
 void LLPanelPreferenceControls::cancel()
@@ -3292,11 +3250,6 @@ void LLPanelPreferenceControls::cancel()
         }
     }
     pControlsTable->clear();
-    if (mHighlightedCell)
-    {
-        mHighlightedCell->setHighlighted(false);
-        mHighlightedCell = NULL;
-    }
 }
 
 void LLPanelPreferenceControls::saveSettings()
@@ -3315,11 +3268,6 @@ void LLPanelPreferenceControls::saveSettings()
     {
         regenerateControls();
     }
-    else if (mHighlightedCell)
-    {
-        mHighlightedCell->setHighlighted(false);
-        mHighlightedCell = NULL;
-    }
 }
 
 void LLPanelPreferenceControls::resetDirtyChilds()
@@ -3329,7 +3277,6 @@ void LLPanelPreferenceControls::resetDirtyChilds()
 
 void LLPanelPreferenceControls::onListCommit()
 {
-    mShowKeyDialog = false;
     LLScrollListItem* item = pControlsTable->getFirstSelected();
     if (item == NULL)
     {
@@ -3340,11 +3287,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;
     }
 
@@ -3352,13 +3308,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();
     }
 }
 
@@ -3375,8 +3345,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);
@@ -3399,10 +3367,7 @@ void LLPanelPreferenceControls::onDefaultKeyBind()
     {
         return;
     }
-
-    pControlsTable->deselectAllItems();
-    pControlsTable->selectByValue(mEditingControl);
-
+    
     if (mEditingColumn > 0)
     {
         mConflictHandler[mEditingMode].resetToDefault(mEditingControl, mEditingColumn - 1);
@@ -3412,11 +3377,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 e07ead7e18..570f1c6caf 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -303,7 +303,6 @@ public:
 	~LLPanelPreferenceControls();
 
 	BOOL postBuild();
-	BOOL handleHover(S32 x, S32 y, MASK mask);
 
 	void apply();
 	void cancel();
@@ -326,12 +325,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 2e656ed358af28f56c8b900345956d431f8c7b4d 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

(limited to 'indra')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index d0cd4e2b39..7cdb41b3cb 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>Enable double-click auto pilot</string>
+      <string>(Obsolete)Enable double-click auto pilot</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -3553,13 +3553,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>
@@ -15559,7 +15559,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 47cc93175e..3668f71feb 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.
@@ -1848,10 +1829,6 @@ void LLFloaterPreference::onChangeQuality(const LLSD& data)
 	refresh();
 }
 
-void LLFloaterPreference::onClickSetKey()
-{
-}
-
 void LLFloaterPreference::onClickSetMiddleMouse()
 {
 	LLUICtrl* p2t_line_editor = getChild<LLUICtrl>("modifier_combo");
@@ -2335,11 +2312,6 @@ void LLFloaterPreference::onClickAdvanced()
 	}
 }
 
-void LLFloaterPreference::onClickActionChange()
-{
-	mClickActionDirty = true;
-}
-
 void LLFloaterPreference::onClickPermsDefault()
 {
 	LLFloaterReg::showInstance("perms_default");
@@ -2377,26 +2349,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()));
@@ -2997,70 +2949,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),
@@ -3078,10 +2966,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");
@@ -3093,47 +2977,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();
@@ -3144,58 +2987,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);
         }
     }
 }
@@ -3211,7 +3070,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)
@@ -3227,6 +3085,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 570f1c6caf..90697341cb 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();
@@ -205,7 +197,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;
@@ -317,7 +308,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 c2defdd772..db88798d6b 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 13a25be08f0c81a759076907d7950baf4f2c3ef2 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

(limited to 'indra')

diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index c266bec777..d97bf2d674 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -3536,6 +3536,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 b47b6a5214..adcb2ca2f9 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -795,6 +795,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 340f1f8a22..111aefe186 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -558,6 +558,7 @@ set(viewer_SOURCE_FILES
     llsecapi.cpp
     llsechandler_basic.cpp
     llselectmgr.cpp
+    llsetkeybinddialog.cpp
     llsettingspicker.cpp
     llsettingsvo.cpp
     llshareavatarhandler.cpp
@@ -1181,6 +1182,7 @@ set(viewer_HEADER_FILES
     llsecapi.h
     llsechandler_basic.h
     llselectmgr.h
+    llsetkeybinddialog.h
     llsettingspicker.h
     llsettingsvo.h
     llsidepanelappearance.h
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 3668f71feb..e71c7d58e2 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 
 
@@ -3197,11 +2896,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)
@@ -3210,6 +2909,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 90697341cb..9c4f6fad46 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;
@@ -286,7 +287,7 @@ private:
 	LOG_CLASS(LLPanelPreferenceGraphics);
 };
 
-class LLPanelPreferenceControls : public LLPanelPreference
+class LLPanelPreferenceControls : public LLPanelPreference, public LLKeyBindResponderInterface
 {
 	LOG_CLASS(LLPanelPreferenceControls);
 public:
@@ -302,7 +303,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 aa5ba3f210..8a3bcf7172 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 1be1c4ba96..d44c81d1a4 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -108,7 +108,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 e211372923bed31e632bc9825913d3d57cdc2d52 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

(limited to 'indra')

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 111aefe186..b8fa60ddcb 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1671,7 +1671,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 7145f0f29c..857cd86739 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1003,11 +1003,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 e71c7d58e2..9e1330dca7 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2875,7 +2875,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)
@@ -2895,6 +2895,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)
 {
@@ -2905,21 +2913,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 9c4f6fad46..8adfb79038 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -292,7 +292,7 @@ class LLPanelPreferenceControls : public LLPanelPreference, public LLKeyBindResp
 	LOG_CLASS(LLPanelPreferenceControls);
 public:
 	LLPanelPreferenceControls();
-	~LLPanelPreferenceControls();
+	virtual ~LLPanelPreferenceControls();
 
 	BOOL postBuild();
 
@@ -303,10 +303,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 8a3bcf7172..d52ad8056f 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 4a06a2012f..02d0dcb6c7 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -1007,7 +1007,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;
@@ -1048,57 +1048,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;
@@ -1117,27 +1090,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)
@@ -1146,23 +1103,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;
 }
@@ -1171,8 +1117,7 @@ LLViewerInput::KeyBinding::KeyBinding()
 :	key("key"),
 	mouse("mouse"),
 	mask("mask"),
-	command("command"),
-	ignore("ignore", false)
+	command("command")
 {}
 
 LLViewerInput::KeyMode::KeyMode()
@@ -1191,10 +1136,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();
     }
 }
 
@@ -1218,6 +1161,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;
@@ -1234,9 +1205,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
@@ -1251,9 +1221,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
@@ -1266,7 +1235,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;
 }
@@ -1291,7 +1264,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,
@@ -1304,7 +1277,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)
@@ -1352,12 +1325,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))
     {
@@ -1445,11 +1413,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)
@@ -1486,11 +1454,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 7cec1f3381291ffbf4cc6a07daf4a74d5af5a9ee 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(-)

(limited to 'indra')

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 02d0dcb6c7..2327ac7f4c 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -1198,10 +1198,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 6597c7696783ce56f89b34a4b6440363635be6a6 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(-)

(limited to 'indra')

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 9e1330dca7..15e6c91ad0 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));	
@@ -1528,21 +1527,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 
@@ -2229,25 +2213,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 8adfb79038..1d6b3a9e1a 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 2327ac7f4c..b847923c9c 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -1311,7 +1311,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 db88798d6b..74c9b10cff 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 62214b53f09c453dc410465ba6e64a772562e6db 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(-)

(limited to 'indra')

diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index d97bf2d674..b87819102b 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);
@@ -3023,6 +3034,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
@@ -3536,27 +3568,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 adcb2ca2f9..8cef9c6463 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;
@@ -635,6 +637,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
@@ -795,8 +798,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 091fc720c1..a6bc3373e2 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"
 
@@ -2730,6 +2731,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 57bf6eafc1d0dc612971ca0ef523cc41c21bec95 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(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index b847923c9c..3ff4e4eb9d 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -652,15 +652,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);
     }
@@ -670,15 +677,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);
     }
@@ -688,15 +702,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);
     }
@@ -706,15 +727,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 7a14cf420397b225d53f9bb3c7544a766627cf5c 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(-)

(limited to 'indra')

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 15e6c91ad0..7cf009c3ef 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2865,6 +2865,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);
     }
 }
 
@@ -2879,6 +2881,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();
@@ -2895,6 +2899,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 fd5c1a1f0787d8464432a8ed592b0d6d9b8da092 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(-)

(limited to 'indra')

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 b5b266c4d2bdf71d89f5d2545e7d6e7966082c90 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(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 857cd86739..4c2de27f42 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1010,7 +1010,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 7cf009c3ef..0abd014a2c 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2618,6 +2618,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);
@@ -2857,17 +2858,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 1d6b3a9e1a..f89923e497 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -308,7 +308,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 73a1877ff0abcba46f66ef55440274119427723b 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(-)

(limited to 'indra')

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 0abd014a2c..50b7f16ec7 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2637,7 +2637,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;
 }
@@ -2659,7 +2659,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";
@@ -2867,20 +2866,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))
     {
@@ -2889,16 +2910,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))
     {
@@ -2907,9 +2944,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 f89923e497..6c2e655270 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -302,9 +302,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 3ff4e4eb9d..9f16b6a4d5 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -936,11 +936,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;
@@ -1155,7 +1150,6 @@ LLViewerInput::KeyMode::KeyMode()
 LLViewerInput::Keys::Keys()
 :	first_person("first_person"),
 	third_person("third_person"),
-	edit("edit"),
 	sitting("sitting"),
 	edit_avatar("edit_avatar")
 {}
@@ -1182,7 +1176,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 8a91a1f721..42d4f46d7f 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -11406,6 +11406,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 9b218acc351cdd2eb06a9f87951314e0eb34daa9 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(-)

(limited to 'indra')

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 3ae6b2484e8008e9b533c0e470ba24ee174325f7 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(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index 9f16b6a4d5..369db33642 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -732,11 +732,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 b58fdec3036f91d97cc12762803fea9f65f673a0 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(-)

(limited to 'indra')

diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 1b54402221..dd429d4ccf 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 b8d5a5f08173f44034a1ecfce86d7b4ff15b4a82 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(-)

(limited to 'indra')

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 e7d383be8a9734a5008690b8a7e1b179e2f2a718 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(-)

(limited to 'indra')

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 50b7f16ec7..0896493f07 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2669,21 +2669,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 5568018bd20a43c30caca0c6288e63bfae29a2e3 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(-)

(limited to 'indra')

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 2022c91e2d1b3d3cbb642c1669d4ac524f31af28 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/llfloateravatarpicker.cpp     | 75 +++++++++++++++++++++++++++--
 indra/newview/llfloateravatarpicker.h       |  9 +++-
 indra/newview/llfloatercolorpicker.cpp      | 11 ++++-
 indra/newview/llfloatercolorpicker.h        | 11 +++--
 indra/newview/llfloaterexperiencepicker.cpp | 15 ++++--
 indra/newview/llfloaterexperiencepicker.h   | 10 +++-
 indra/newview/lltexturectrl.cpp             |  6 ++-
 indra/newview/lltexturectrl.h               |  6 +--
 9 files changed, 123 insertions(+), 22 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index b8fa60ddcb..00d19e3ba4 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
@@ -812,7 +811,6 @@ set(viewer_HEADER_FILES
     lldonotdisturbnotificationstorage.h
     lldndbutton.h
     lldrawable.h
-    lldrawfrustum.h
     lldrawpool.h
     lldrawpoolalpha.h
     lldrawpoolavatar.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 273dfe72d6..1a784223c2 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()
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 54d27be825..c642da7b83 100644
--- a/indra/newview/llfloaterexperiencepicker.cpp
+++ b/indra/newview/llfloaterexperiencepicker.cpp
@@ -64,7 +64,10 @@ LLFloaterExperiencePicker* LLFloaterExperiencePicker::show( select_callback_t ca
 		floater->mSearchPanel->filterContent();
 	}
 
-	floater->setFrustumOrigin(frustumOrigin);
+	if(frustumOrigin)
+	{
+		floater->mFrustumOrigin = frustumOrigin->getHandle();
+	}
 
 	return floater;
 }
@@ -77,15 +80,21 @@ void LLFloaterExperiencePicker::drawFrustum()
 
 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 7fcc1f4977..1f128f22d9 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()
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 0d78aa31e2bd2cf55c83a4447027a94b0939ae26 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/newview/llfloateravatarpicker.cpp | 55 ++-------------------------------
 indra/newview/llsetkeybinddialog.cpp    | 21 ++++++++++---
 indra/newview/llsetkeybinddialog.h      | 13 ++++++--
 indra/newview/lltexturectrl.cpp         |  3 --
 4 files changed, 30 insertions(+), 62 deletions(-)

(limited to 'indra')

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/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 1f128f22d9..9e7846f8c9 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;
 
-- 
cgit v1.2.3


From 708fdb4e67393dbf03a0e0c82608d62f1868926a 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(-)

(limited to 'indra')

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 369db33642..da61a9b39b 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -924,7 +924,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")
 	{
@@ -953,7 +954,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 1bfac6aeb7..cd639ded36 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -4088,6 +4088,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 0b07e057b10baa94233347f1bff7b9dc66ade9bc 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/newview/llviewerinput.cpp | 8 ++++----
 indra/newview/llviewermedia.h   | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index da61a9b39b..bbaa4f2916 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -785,16 +785,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 9467a138f0..a5cde35c88 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -79,7 +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* 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;
-- 
cgit v1.2.3


From e6abf3dcb211940a7cec07ae910296611cd16288 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(+)

(limited to 'indra')

diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index bbaa4f2916..ad4b9d4215 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 74a303b2791f046e5804db801e53c33f716d9ef3 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(-)

(limited to 'indra')

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 bcaf860e7e37bd3f0c48be9d4b94e0912d52b3f1 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(-)

(limited to 'indra')

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 629cd92c47e90a1fb8711c46bd406476d01e9b9b 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

(limited to 'indra')

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 0896493f07..42defac250 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 c604b274fb4ab218a89fc03a4ea5cc1b739ad65f 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

(limited to 'indra')

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 42defac250..604f054aa5 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 6092e2ffab9ec76bdd8821e188db9cb785456eee 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(-)

(limited to 'indra')

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 4c2de27f42..911cc224a1 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 e578491be761fefa34e4041458e2cf5badc81873 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(-)

(limited to 'indra')

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 604f054aa5..ac2b0172c7 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 74aba5768e62f2260ac44c5244145a0a689bf3d5 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(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 911cc224a1..adbd81aae3 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 ac2b0172c7..697e3253df 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 df306eec5b9479dac72418bdd8c42a4f328e4f2b 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(-)

(limited to 'indra')

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 f6662ffb26208a40f7c823c67e53f36b0267b71c 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(-)

(limited to 'indra')

diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 697e3253df..b8edf4ad84 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 f08c8ef2082e193cf3822d76357b60f133130afc 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(-)

(limited to 'indra')

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 7717097f7cfa1deaa934b9846c22523f53c600d3 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 23 Jun 2020 20:29:00 +0300
Subject: SL-6109 Teleport and autopilot should not work in some cases

Hides teleport_to and walk_to also optimizes couple things.
---
 indra/newview/llappviewer.cpp                      | 22 +++++-
 indra/newview/llfloaterpreference.cpp              | 79 ++++++++++++++--------
 indra/newview/llkeyconflict.cpp                    | 28 +++++++-
 indra/newview/llkeyconflict.h                      |  1 +
 .../xui/en/control_table_contents_camera.xml       | 62 +++++++++++++++++
 .../en/control_table_contents_camera_sitting.xml   | 65 ------------------
 6 files changed, 161 insertions(+), 96 deletions(-)
 delete mode 100644 indra/newview/skins/default/xui/en/control_table_contents_camera_sitting.xml

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index adbd81aae3..e20c9e663c 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1021,6 +1021,7 @@ bool LLAppViewer::init()
         LL_INFOS("InitInfo") << "Converting legacy mouse bindings to new format" << LL_ENDL;
         // Load settings from file
         LLKeyConflictHandler third_person_view(LLKeyConflictHandler::MODE_THIRD_PERSON);
+        LLKeyConflictHandler sitting_view(LLKeyConflictHandler::MODE_SITTING);
 
         // Since we are only modifying keybindings if personal file doesn't exist yet,
         // it should be safe to just overwrite the value
@@ -1050,6 +1051,14 @@ bool LLAppViewer::init()
                                           MASK_NONE,
                                           value);
 
+        // sitting also supports teleport
+        sitting_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;
@@ -1073,6 +1082,7 @@ bool LLAppViewer::init()
         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);
+        sitting_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true);
 
         if (third_person_view.hasUnsavedChanges())
         {
@@ -1080,12 +1090,18 @@ bool LLAppViewer::init()
             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)
+        if (sitting_view.hasUnsavedChanges())
+        {
+            // calls loadBindingsXML()
+            sitting_view.saveToSettings();
+        }
+
+        // in case of voice we need to repeat this in other modes
 
         for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
         {
-            if (i != LLKeyConflictHandler::MODE_THIRD_PERSON)
+            // edit and first person modes; MODE_SAVED_SETTINGS not in use at the moment
+            if (i != LLKeyConflictHandler::MODE_THIRD_PERSON && i != LLKeyConflictHandler::MODE_SITTING)
             {
                 LLKeyConflictHandler handler((LLKeyConflictHandler::ESourceMode)i);
 
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index b8edf4ad84..f4a19d06b0 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -2801,20 +2801,34 @@ bool LLPanelPreferenceControls::addControlTableRows(const std::string &filename)
         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 show = true;
             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);
+            if (!enabled)
+            {
+                // If empty: this is a placeholder to make sure user won't assign
+                // value by accident, don't show it
+                // If not empty: predefined control combination user should see
+                // to know that combination is reserved
+                show = !mConflictHandler[mEditingMode].isControlEmpty(control);
+                // example: teleport_to and walk_to in first person view, and
+                // sitting related functions, see generatePlaceholders()
+            }
+
+            if (show)
+            {
+                // At the moment viewer is hardcoded to assume that columns are named as lst_ctrl%d
+                LLScrollListItem::Params item_params(*row_it);
+                item_params.enabled.setValue(enabled);
+
+                S32 num_columns = pControlsTable->getNumColumns();
+                for (S32 col = 1; col < num_columns; col++)
+                {
+                    cell_params.column = llformat("lst_ctrl%d", col);
+                    cell_params.value = mConflictHandler[mEditingMode].getControlString(control, col - 1);
+                    item_params.columns.add(cell_params);
+                }
+                pControlsTable->addRow(item_params, EAddPosition::ADD_BOTTOM);
+            }
         }
         else
         {
@@ -2825,7 +2839,8 @@ bool LLPanelPreferenceControls::addControlTableRows(const std::string &filename)
             //   type = "icon"
             //   color = "0 0 0 0.7"
             //   halign = "center"
-            //   value = "menu_separator" />
+            //   value = "menu_separator"
+            //   column = "lst_action" / >
             //</rows>
             pControlsTable->addRow(*row_it, EAddPosition::ADD_BOTTOM);
         }
@@ -2835,7 +2850,16 @@ bool LLPanelPreferenceControls::addControlTableRows(const std::string &filename)
 
 void LLPanelPreferenceControls::addControlTableSeparator()
 {
-    pControlsTable->addSeparator(EAddPosition::ADD_BOTTOM);
+    LLScrollListItem::Params separator_params;
+    separator_params.enabled(false);
+    LLScrollListCell::Params column_params;
+    column_params.type = "icon";
+    column_params.value = "menu_separator";
+    column_params.column = "lst_action";
+    column_params.color = LLColor4(0.f, 0.f, 0.f, 0.7f);
+    column_params.font_halign = LLFontGL::HCENTER;
+    separator_params.columns.add(column_params);
+    pControlsTable->addRow(separator_params, EAddPosition::ADD_BOTTOM);
 }
 
 void LLPanelPreferenceControls::populateControlTable()
@@ -2843,7 +2867,7 @@ void LLPanelPreferenceControls::populateControlTable()
     pControlsTable->clearRows();
     pControlsTable->clearColumns();
 
-    // add columns
+    // Add columns
     std::string filename;
     switch ((LLKeyConflictHandler::ESourceMode)mEditingMode)
     {
@@ -2861,9 +2885,11 @@ void LLPanelPreferenceControls::populateControlTable()
     }
     addControlTableColumns(filename);
 
-
+    // Add rows.
+    // Each file represents individual visual group (movement/camera/media...)
     if (mEditingMode == LLKeyConflictHandler::MODE_FIRST_PERSON)
     {
+        // Don't display whole camera and editing groups
         addControlTableRows("control_table_contents_movement.xml");
         addControlTableSeparator();
         addControlTableRows("control_table_contents_media.xml");
@@ -2872,14 +2898,11 @@ void LLPanelPreferenceControls::populateControlTable()
     else if (mEditingMode < LLKeyConflictHandler::MODE_SAVED_SETTINGS)
     {
         // In case of 'sitting' mode, movements still apply due to vehicles
+        // but walk_to is not supported and will be hidden by addControlTableRows
         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");
@@ -2903,12 +2926,14 @@ void LLPanelPreferenceControls::updateTable()
         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));
+            LLScrollListCell* cell = NULL;
+
+            S32 num_columns = pControlsTable->getNumColumns();
+            for (S32 col = 1; col < num_columns; col++)
+            {
+                cell = list[i]->getColumn(col);
+                cell->setValue(mConflictHandler[mEditingMode].getControlString(control, col - 1));
+            }
         }
     }
     pControlsTable->deselectAllItems();
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index 8ee50d5c52..b6107eeedf 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -243,6 +243,15 @@ LLKeyData LLKeyConflictHandler::getControl(const std::string &control_name, U32
     return mControlsMap[control_name].getKeyData(index);
 }
 
+bool LLKeyConflictHandler::isControlEmpty(const std::string &control_name)
+{
+    if (control_name.empty())
+    {
+        return true;
+    }
+    return mControlsMap[control_name].mKeyBind.isEmpty();
+}
+
 // static
 std::string LLKeyConflictHandler::getStringFromKeyData(const LLKeyData& keydata)
 {
@@ -885,10 +894,27 @@ void LLKeyConflictHandler::generatePlaceholders(ESourceMode load_mode)
         registerTemporaryControl("edit_avatar_spin_under");
         registerTemporaryControl("edit_avatar_move_forward");
         registerTemporaryControl("edit_avatar_move_backward");
+
+        // no autopilot or teleport
+        registerTemporaryControl("walk_to");
+        registerTemporaryControl("teleport_to");
+    }
+
+    if (load_mode == MODE_EDIT_AVATAR)
+    {
+        // no autopilot or teleport
+        registerTemporaryControl("walk_to");
+        registerTemporaryControl("teleport_to");
     }
 
-    if (load_mode != MODE_SITTING)
+    if (load_mode == MODE_SITTING)
+    {
+        // no autopilot
+        registerTemporaryControl("walk_to");
+    }
+    else 
     {
+        // sitting related functions should only be avaliable in sitting mode
         registerTemporaryControl("move_forward_sitting");
         registerTemporaryControl("move_backward_sitting");
         registerTemporaryControl("spin_over_sitting");
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index 7566303cdd..2926ca3aeb 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -98,6 +98,7 @@ public:
     bool clearControl(const std::string &control_name, U32 data_index);
 
     LLKeyData getControl(const std::string &control_name, U32 data_index);
+    bool isControlEmpty(const std::string &control_name);
 
     // localized string
     static std::string getStringFromKeyData(const LLKeyData& keydata);
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 aba81e3134..24cbb2b885 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
@@ -175,4 +175,66 @@
          tool_tip="Camera spin around clockwise"
          value="Clockwise" />
     </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_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_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>
-- 
cgit v1.2.3


From 7e0254ecd5923a488e69036c256a05890193524c Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Thu, 28 Nov 2019 17:09:34 +0200
Subject: SL-6109 Fixed issue with llcontrols ignoring left mouse button with
 masks

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

(limited to 'indra')

diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp
index ecfc289cb3..38696c2258 100644
--- a/indra/llcommon/llkeybind.cpp
+++ b/indra/llcommon/llkeybind.cpp
@@ -144,7 +144,7 @@ bool LLKeyData::canHandle(const LLKeyData& data) const
 {
     if (data.mKey == mKey
         && data.mMouse == mMouse
-        && ((mIgnoreMasks && (data.mMask & mMask) == data.mMask) || data.mMask == mMask))
+        && ((mIgnoreMasks && (data.mMask & mMask) == mMask) || data.mMask == mMask))
     {
         return true;
     }
@@ -155,7 +155,7 @@ bool LLKeyData::canHandle(EMouseClickType mouse, KEY key, MASK mask) const
 {
     if (mouse == mMouse
         && key == mKey
-        && ((mIgnoreMasks && (mask & mMask) == mask) || mask == mMask))
+        && ((mIgnoreMasks && (mask & mMask) == mMask) || mask == mMask))
     {
         return true;
     }
-- 
cgit v1.2.3


From 703cbef8ab07db9fe65a39c577377a3e40f63728 Mon Sep 17 00:00:00 2001
From: maxim_productengine <mnikolenko@productengine.com>
Date: Tue, 21 Jan 2020 17:02:53 +0200
Subject: SL-12494 Add some more key bindings

---
 indra/newview/skins/default/xui/en/menu_viewer.xml | 31 +++++++++++++++++-----
 1 file changed, 24 insertions(+), 7 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 873b95926b..c7ab26bc22 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -56,7 +56,8 @@
       </menu_item_call>
       <menu_item_call
        label="Places..."
-       name="Places">
+       name="Places"
+       shortcut="control|L">
         <menu_item_call.on_click
          function="Floater.ToggleOrBringToFront"
          parameter="places" />
@@ -85,11 +86,22 @@
       <menu_item_separator/>
       <menu_item_call
        label="Camera Controls..."
-       name="Camera Controls">
+       name="Camera Controls"
+       shortcut="control|K">
         <menu_item_call.on_click
          function="Floater.ToggleOrBringToFront"
          parameter="camera" />
       </menu_item_call>
+      <menu_item_call
+       label="Hover Height"
+       name="HoverHeight"
+       shortcut="alt|control|H"
+       visible="false">
+        <menu_item_call.on_click
+         function="HoverHeight"/>
+        <menu_item_call.on_enable
+         function="Edit.EnableHoverHeight"/>
+      </menu_item_call>
       <menu
        create_jump_keys="true"
        label="Movement"
@@ -150,7 +162,8 @@
         </menu_item_check>
         <menu_item_call
          label="Stop Animating Me"
-         name="Stop Animating My Avatar">
+         name="Stop Animating My Avatar"
+         shortcut="alt|shift|A">
           <menu_item_call.on_click
            function="Tools.StopAllAnimations" />
         </menu_item_call>
@@ -458,7 +471,8 @@
         </menu_item_check>
         <menu_item_call
              label="Events"
-             name="Events">
+             name="Events"
+             shortcut="control|E">
             <menu_item_call.on_click
              function="Advanced.ShowURL"
              parameter="https://secondlife.com/my/community/events"/>
@@ -647,7 +661,8 @@
          tear_off="true">
             <menu_item_check
              label="Sunrise"
-             name="Sunrise">
+             name="Sunrise"
+             shortcut="control|shift|O">
                 <menu_item_check.on_click
                  function="World.EnvSettings"
                  parameter="sunrise" />
@@ -679,7 +694,8 @@
             </menu_item_check>
             <menu_item_check
              label="Midnight"
-             name="Midnight">
+             name="Midnight"
+             shortcut="control|shift|Z">
                 <menu_item_check.on_click
                  function="World.EnvSettings"
                  parameter="midnight" />
@@ -1317,7 +1333,8 @@ function="World.EnvPreset"
             <menu_item_call
            label="Model..."
            layout="topleft"
-           name="Upload Model">
+           name="Upload Model"
+           shortcut="alt|control|U">
             <menu_item_call.on_click
              function="File.UploadModel"
              parameter="" />
-- 
cgit v1.2.3


From 5f06438a97bcb5490abc672f6c25ae16b84b7ec2 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 11 Aug 2020 17:08:12 +0300
Subject: Buildfix

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

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 59f214d641..016919d218 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1014,7 +1014,7 @@ 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 (LLVersionInfo::getChannelAndVersion() != gLastRunVersion
+    if (LLVersionInfo::getInstance()->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
-- 
cgit v1.2.3


From b102ee2dddf948679d11412a84e958dc61ad7211 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Tue, 18 Aug 2020 18:02:36 +0300
Subject: SL-13801 The"Hover Height" floater should be closed after pressing
 the "Ctrl-alt-H" shortcut keys

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

(limited to 'indra')

diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index c7ab26bc22..181f529893 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -98,7 +98,8 @@
        shortcut="alt|control|H"
        visible="false">
         <menu_item_call.on_click
-         function="HoverHeight"/>
+         function="Floater.ToggleOrBringToFront"
+         parameter="edit_hover_height"/>
         <menu_item_call.on_enable
          function="Edit.EnableHoverHeight"/>
       </menu_item_call>
-- 
cgit v1.2.3


From c98bef9717a5ac70e0fe92bd217dbfc9c4094b0d Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 19 Aug 2020 00:05:00 +0300
Subject: SL-13802 Avatar was turned into wrong direction when hitting esc

---
 indra/newview/llagentcamera.cpp | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index 9e65409256..c9d2b8305a 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -2690,10 +2690,19 @@ void LLAgentCamera::setFocusOnAvatar(BOOL focus_on_avatar, BOOL animate, BOOL re
 			LLVector3 at_axis;
 			if (!isAgentAvatarValid() || !gAgentAvatarp->getParent())
 			{
-				at_axis = LLViewerCamera::getInstance()->getAtAxis();
-				at_axis.mV[VZ] = 0.f;
-				at_axis.normalize();
-				gAgent.resetAxes(at_axis);
+                // In case of front view rotate agent to look into direction opposite to camera
+                // In case of rear view rotate agent into diraction same as camera, e t c
+                LLVector3 vect = getCameraOffsetInitial();
+                F32 rotxy = F32(atan2(vect.mV[VY], vect.mV[VX]));
+
+                LLCoordFrame frameCamera = *((LLCoordFrame*)LLViewerCamera::getInstance());
+                // front view angle rotxy is zero, rear view rotxy angle is 180, compensate
+                frameCamera.yaw((180 * DEG_TO_RAD) - rotxy);
+                at_axis = frameCamera.getAtAxis();
+                at_axis.mV[VZ] = 0.f;
+                at_axis.normalize();
+                gAgent.resetAxes(at_axis);
+                gAgent.yaw(0);
 			}
 		}
 	}
-- 
cgit v1.2.3


From e05338cf76bedae176b7ed41c7960d20308e3f59 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Wed, 19 Aug 2020 14:11:59 +0300
Subject: SL-13803 FIXED Objects do not link with the"Ctrl+L" shortcut keys

---
 indra/newview/llviewermenu.cpp                     | 14 +++++++++++++-
 indra/newview/skins/default/xui/en/menu_viewer.xml |  3 +--
 2 files changed, 14 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index ab054fabde..faef7d5b45 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -4595,6 +4595,18 @@ void handle_take_copy()
 	derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id);
 }
 
+void handle_link_objects()
+{
+	if (LLSelectMgr::getInstance()->getSelection()->isEmpty())
+	{
+		LLFloaterReg::toggleInstanceOrBringToFront("places");
+	}
+	else
+	{
+		LLSelectMgr::getInstance()->linkObjects();
+	}
+}
+
 // You can return an object to its owner if it is on your land.
 class LLObjectReturn : public view_listener_t
 {
@@ -8980,7 +8992,7 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY");
 	view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid");
 	view_listener_t::addMenu(new LLToolsSelectNextPartFace(), "Tools.SelectNextPart");
-	commit.add("Tools.Link", boost::bind(&LLSelectMgr::linkObjects, LLSelectMgr::getInstance()));
+	commit.add("Tools.Link", boost::bind(&handle_link_objects));
 	commit.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance()));
 	view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations");
 	view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys");
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 181f529893..aab47d0d0d 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -59,8 +59,7 @@
        name="Places"
        shortcut="control|L">
         <menu_item_call.on_click
-         function="Floater.ToggleOrBringToFront"
-         parameter="places" />
+         function="Tools.Link"/>
       </menu_item_call>
       <menu_item_call
        label="Picks..."
-- 
cgit v1.2.3


From bf48c9103e9d10bbce653da12c2b325055efd15b Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Wed, 19 Aug 2020 15:40:28 +0300
Subject: SL-13799 Use macOS control key for "Hover Height" shortcut

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

(limited to 'indra')

diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index aab47d0d0d..5f52b79f4a 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -95,6 +95,7 @@
        label="Hover Height"
        name="HoverHeight"
        shortcut="alt|control|H"
+       use_mac_ctrl="true"
        visible="false">
         <menu_item_call.on_click
          function="Floater.ToggleOrBringToFront"
-- 
cgit v1.2.3


From e566e82269ff52a88e3dc28345bba6c273a2eebf Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 19 Aug 2020 20:41:46 +0300
Subject: SL-13800 Made 'stop animation' continuous

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

(limited to 'indra')

diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 5f52b79f4a..089742a4ee 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -164,6 +164,7 @@
         <menu_item_call
          label="Stop Animating Me"
          name="Stop Animating My Avatar"
+         allow_key_repeat="true"
          shortcut="alt|shift|A">
           <menu_item_call.on_click
            function="Tools.StopAllAnimations" />
-- 
cgit v1.2.3


From 3f51c0423942f61d27c33bfdb1622e5ae2b8c9ae Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Mon, 19 Oct 2020 14:09:23 +0300
Subject: SL-14139 disallow Gestures from being bound to Ctrl+F10

---
 indra/newview/llpreviewgesture.cpp | 19 +++++++++++++++++--
 indra/newview/llpreviewgesture.h   |  2 ++
 2 files changed, 19 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp
index 70ce275734..18c2fb5452 100644
--- a/indra/newview/llpreviewgesture.cpp
+++ b/indra/newview/llpreviewgesture.cpp
@@ -373,11 +373,11 @@ BOOL LLPreviewGesture::postBuild()
 	mReplaceEditor = edit;
 
 	combo = getChild<LLComboBox>( "modifier_combo");
-	combo->setCommitCallback(onCommitSetDirty, this);
+	combo->setCommitCallback(boost::bind(&LLPreviewGesture::onCommitKeyorModifier, this));
 	mModifierCombo = combo;
 
 	combo = getChild<LLComboBox>( "key_combo");
-	combo->setCommitCallback(onCommitSetDirty, this);
+	combo->setCommitCallback(boost::bind(&LLPreviewGesture::onCommitKeyorModifier, this));
 	mKeyCombo = combo;
 
 	list = getChild<LLScrollListCtrl>("library_list");
@@ -937,12 +937,16 @@ void LLPreviewGesture::loadUIFromGesture(LLMultiGesture* gesture)
 		break;
 	}
 
+	mModifierCombo->setEnabledByValue(CTRL_LABEL, gesture->mKey != KEY_F10);
+
 	mKeyCombo->setCurrentByIndex(0);
 	if (gesture->mKey != KEY_NONE)
 	{
 		mKeyCombo->setSimple(LLKeyboard::stringFromKey(gesture->mKey));
 	}
 
+	mKeyCombo->setEnabledByValue(LLKeyboard::stringFromKey(KEY_F10), gesture->mMask != MASK_CONTROL);
+
 	// Make UI steps for each gesture step
 	S32 i;
 	S32 count = gesture->mSteps.size();
@@ -1338,6 +1342,17 @@ LLMultiGesture* LLPreviewGesture::createGesture()
 }
 
 
+void LLPreviewGesture::onCommitKeyorModifier()
+{
+	// SL-14139: ctrl-F10 is currently used to access top menu,
+	// so don't allow to bound gestures to this combination.
+
+	mKeyCombo->setEnabledByValue(LLKeyboard::stringFromKey(KEY_F10), mModifierCombo->getSimple() != CTRL_LABEL);
+	mModifierCombo->setEnabledByValue(CTRL_LABEL, mKeyCombo->getSimple() != LLKeyboard::stringFromKey(KEY_F10));
+	mDirty = TRUE;
+	refresh();
+}
+
 // static
 void LLPreviewGesture::updateLabel(LLScrollListItem* item)
 {
diff --git a/indra/newview/llpreviewgesture.h b/indra/newview/llpreviewgesture.h
index 3ba4f56295..ffcada4cc2 100644
--- a/indra/newview/llpreviewgesture.h
+++ b/indra/newview/llpreviewgesture.h
@@ -103,6 +103,8 @@ protected:
 	LLScrollListItem* addStep(const enum EStepType step_type);
 	
 	void onVisibilityChanged ( const LLSD& new_visibility );
+
+	void onCommitKeyorModifier();
 	
 	static std::string getLabel(std::vector<std::string> labels);
 	static void updateLabel(LLScrollListItem* item);
-- 
cgit v1.2.3


From 47434d85b7dca5cdfef04d1a646d54903e6dea9d Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 13 Nov 2020 21:50:26 +0200
Subject: SL-14271 Alt Gr should not trigger menu when inputing characters

---
 indra/newview/llviewerwindow.cpp | 68 ++++++++++++++++++++++++++++++++--------
 1 file changed, 55 insertions(+), 13 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index d2d36b8306..93f8cce5c7 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2747,22 +2747,64 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
     }
 
     LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
-
+    
     if (keyboard_focus
-		&& !(mask & (MASK_CONTROL | MASK_ALT))
-		&& !gFocusMgr.getKeystrokesOnly())
-	{
-		// We have keyboard focus, and it's not an accelerator
-        if (keyboard_focus && keyboard_focus->wantsKeyUpKeyDown())
+        && !gFocusMgr.getKeystrokesOnly())
+    {
+#ifdef LL_WINDOWS
+        // On windows Alt Gr key generates additional Ctrl event, as result handling situations
+        // like 'AltGr + D' will result in 'Alt+Ctrl+D'. If it results in WM_CHAR, don't let it
+        // pass into menu or it will trigger 'develop' menu assigned to this combination on top
+        // of character handling.
+        // Alt Gr can be additionally modified by Shift
+        const MASK alt_gr = MASK_CONTROL | MASK_ALT;
+        if ((mask & alt_gr) != 0
+            && key >= 0x30
+            && key <= 0x5A
+            && (GetKeyState(VK_RMENU) & 0x8000) != 0
+            && (GetKeyState(VK_RCONTROL) & 0x8000) == 0) // ensure right control is not pressed, only left one
         {
-            return keyboard_focus->handleKey(key, mask, FALSE );
+            // Alt Gr key is represented as right alt and left control.
+            // Any alt+ctrl combination is treated as Alt Gr by TranslateMessage() and
+            // will generate a WM_CHAR message, but here we only treat virtual Alt Graph
+            // key by checking if this specific combination has unicode char.
+            //
+            // I decided to handle only virtual RAlt+LCtrl==AltGr combination to minimize
+            // impact on menu, but the right way might be to handle all Alt+Ctrl calls.
+
+            BYTE keyboard_state[256];
+            if (GetKeyboardState(keyboard_state))
+            {
+                const int char_count = 6;
+                wchar_t chars[char_count];
+                HKL layout = GetKeyboardLayout(0);
+                // ToUnicodeEx changes buffer state on OS below Win10, which is undesirable,
+                // but since we already did a TranslateMessage() in gatherInput(), this
+                // should have no negative effect
+                int res = ToUnicodeEx(key, 0, keyboard_state, chars, char_count, 1 << 2 /*do not modify buffer flag*/, layout);
+                if (res == 1 && chars[0] >= 0x20)
+                {
+                    // Let it fall through to character handler and get a WM_CHAR.
+                    return TRUE;
+                }
+            }
         }
-		else if (key < 0x80)
-		{
-			// Not a special key, so likely (we hope) to generate a character.  Let it fall through to character handler first.
-            return (keyboard_focus != NULL);
-		}
-	}
+#endif
+
+        if (!(mask & (MASK_CONTROL | MASK_ALT)))
+        {
+            // We have keyboard focus, and it's not an accelerator
+            if (keyboard_focus && keyboard_focus->wantsKeyUpKeyDown())
+            {
+                return keyboard_focus->handleKey(key, mask, FALSE);
+            }
+            else if (key < 0x80)
+            {
+                // Not a special key, so likely (we hope) to generate a character.  Let it fall through to character handler first.
+                return TRUE;
+            }
+        }
+    }
 
 	// let menus handle navigation keys for navigation
 	if ((gMenuBarView && gMenuBarView->handleKey(key, mask, TRUE))
-- 
cgit v1.2.3


From dd887e24d5afd103f3b7b5ca756daad50c46953e Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Tue, 17 Nov 2020 14:15:06 +0200
Subject: SL-14342 FIXED Crash: "Uninitialized param singleton LLVoiceClient"

---
 indra/newview/llappviewer.cpp     | 257 +++++++++++++++++++-------------------
 indra/newview/llappviewer.h       |   2 +
 indra/newview/llstartup.cpp       |   5 +-
 indra/newview/llviewercontrol.cpp |   5 +-
 4 files changed, 141 insertions(+), 128 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index f29d985915..ab31dc096d 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1005,132 +1005,6 @@ 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::getInstance()->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);
-        LLKeyConflictHandler sitting_view(LLKeyConflictHandler::MODE_SITTING);
-
-        // 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);
-
-        // sitting also supports teleport
-        sitting_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);
-        sitting_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true);
-
-        if (third_person_view.hasUnsavedChanges())
-        {
-            // calls loadBindingsXML()
-            third_person_view.saveToSettings();
-        }
-
-        if (sitting_view.hasUnsavedChanges())
-        {
-            // calls loadBindingsXML()
-            sitting_view.saveToSettings();
-        }
-
-        // in case of voice we need to repeat this in other modes
-
-        for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
-        {
-            // edit and first person modes; MODE_SAVED_SETTINGS not in use at the moment
-            if (i != LLKeyConflictHandler::MODE_THIRD_PERSON && i != LLKeyConflictHandler::MODE_SITTING)
-            {
-                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
-		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;
-		}
-	}
-
 	// If we don't have the right GL requirements, exit.
 	if (!gGLManager.mHasRequirements)
 	{
@@ -1385,6 +1259,9 @@ bool LLAppViewer::init()
 	joystick = LLViewerJoystick::getInstance();
 	joystick->setNeedsReset(true);
 
+	// Load User's bindings
+	loadKeyBindings();
+
 	return true;
 }
 
@@ -4500,6 +4377,134 @@ void LLAppViewer::addOnIdleCallback(const boost::function<void()>& cb)
 	LLDeferredTaskList::instance().addTask(cb);
 }
 
+void LLAppViewer::loadKeyBindings()
+{
+	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::getInstance()->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);
+		LLKeyConflictHandler sitting_view(LLKeyConflictHandler::MODE_SITTING);
+
+		// 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);
+
+		// sitting also supports teleport
+		sitting_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);
+		sitting_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true);
+
+		if (third_person_view.hasUnsavedChanges())
+		{
+			// calls loadBindingsXML()
+			third_person_view.saveToSettings();
+		}
+
+		if (sitting_view.hasUnsavedChanges())
+		{
+			// calls loadBindingsXML()
+			sitting_view.saveToSettings();
+		}
+
+		// in case of voice we need to repeat this in other modes
+
+		for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
+		{
+			// edit and first person modes; MODE_SAVED_SETTINGS not in use at the moment
+			if (i != LLKeyConflictHandler::MODE_THIRD_PERSON && i != LLKeyConflictHandler::MODE_SITTING)
+			{
+				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
+		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;
+		}
+	}
+}
+
 void LLAppViewer::purgeCache()
 {
 	LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << LL_ENDL;
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 8f0f54de3b..69bc940312 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -194,6 +194,8 @@ public:
 	void purgeCache(); // Clear the local cache. 
 	void purgeCacheImmediate(); //clear local cache immediately.
 	S32  updateTextureThreads(F32 max_time);
+
+	void loadKeyBindings();
 	
 	// mute/unmute the system's master audio
 	virtual void setMasterSystemAudioMute(bool mute);
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 17777c3ceb..e2a39bdf86 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -1425,7 +1425,10 @@ bool idle_startup()
 
 		// update the voice settings *after* gCacheName initialization
 		// so that we can construct voice UI that relies on the name cache
-		LLVoiceClient::getInstance()->updateSettings();
+		if (LLVoiceClient::instanceExists())
+		{
+			LLVoiceClient::getInstance()->updateSettings();
+		}
 		display_startup();
 
 		// create a container's instance for start a controlling conversation windows
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 8aa5b07561..76dc9a6790 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -510,7 +510,10 @@ bool handleHighResSnapshotChanged(const LLSD& newvalue)
 
 bool handleVoiceClientPrefsChanged(const LLSD& newvalue)
 {
-	LLVoiceClient::getInstance()->updateSettings();
+	if (LLVoiceClient::instanceExists())
+	{
+		LLVoiceClient::getInstance()->updateSettings();
+	}
 	return true;
 }
 
-- 
cgit v1.2.3


From 9abac37e42781aaacfc9331627182c2e83f98fd9 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 2 Dec 2020 13:48:27 +0200
Subject: SL-14438 Fixed Viewer lost ability to assign Masks as keys

---
 indra/newview/llsetkeybinddialog.cpp | 41 +++++++++++++++++++++++++++++-------
 indra/newview/llsetkeybinddialog.h   |  6 +++---
 indra/newview/llviewerwindow.cpp     | 12 +++++++++--
 3 files changed, 46 insertions(+), 13 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp
index 4eb76c9d89..a7f005ec19 100644
--- a/indra/newview/llsetkeybinddialog.cpp
+++ b/indra/newview/llsetkeybinddialog.cpp
@@ -164,14 +164,14 @@ void LLSetKeyBindDialog::setParent(LLKeyBindResponderInterface* parent, LLView*
 }
 
 // static
-bool LLSetKeyBindDialog::recordKey(KEY key, MASK mask)
+bool LLSetKeyBindDialog::recordKey(KEY key, MASK mask, BOOL down)
 {
     if (sRecordKeys)
     {
         LLSetKeyBindDialog* dialog = LLFloaterReg::getTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD());
         if (dialog && dialog->getVisible())
         {
-            return dialog->recordAndHandleKey(key, mask);
+            return dialog->recordAndHandleKey(key, mask, down);
         }
         else
         {
@@ -182,7 +182,7 @@ bool LLSetKeyBindDialog::recordKey(KEY key, MASK mask)
     return false;
 }
 
-bool LLSetKeyBindDialog::recordAndHandleKey(KEY key, MASK mask)
+bool LLSetKeyBindDialog::recordAndHandleKey(KEY key, MASK mask, BOOL down)
 {
     if ((key == 'Q' && mask == MASK_CONTROL)
         || key == KEY_ESCAPE)
@@ -208,13 +208,35 @@ bool LLSetKeyBindDialog::recordAndHandleKey(KEY key, MASK mask)
         return false;
     }
 
-    if ((mKeyFilterMask & ALLOW_MASKS) == 0
-        && (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT))
+    if (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT)
     {
-        // mask by themself are not allowed
-        return false;
+        // Mask keys get special treatment
+        if (down == TRUE)
+        {
+            // Most keys are handled on 'down' event because menu is handled on 'down'
+            // masks are exceptions to let other keys be handled
+            return false;
+        }
+        if ((mKeyFilterMask & ALLOW_MASKS) == 0)
+        {
+            // Mask by themself are not allowed
+            return false;
+        }
+        // Mask up event often generates things like 'shift key + shift mask', filter it out.
+        if (key == KEY_CONTROL)
+        {
+            mask &= ~MASK_CONTROL;
+        }
+        if (key == KEY_SHIFT)
+        {
+            mask &= ~MASK_SHIFT;
+        }
+        if (key == KEY_ALT)
+        {
+            mask &= ~MASK_ALT;
+        }
     }
-    else if ((mKeyFilterMask & ALLOW_KEYS) == 0)
+    if ((mKeyFilterMask & ALLOW_KEYS) == 0)
     {
         // basic keys not allowed
         return false;
@@ -233,6 +255,9 @@ bool LLSetKeyBindDialog::recordAndHandleKey(KEY key, MASK mask)
     }
 
     setKeyBind(CLICK_NONE, key, mask, pCheckBox->getValue().asBoolean());
+    // Note/Todo: To warranty zero interference we should also consume
+    // an 'up' event if we recorded on 'down', not just close floater
+    // on first recorded combination.
     sRecordKeys = false;
     closeFloater();
     return true;
diff --git a/indra/newview/llsetkeybinddialog.h b/indra/newview/llsetkeybinddialog.h
index 70190230e4..ec3c813a66 100644
--- a/indra/newview/llsetkeybinddialog.h
+++ b/indra/newview/llsetkeybinddialog.h
@@ -39,7 +39,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 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_MASKS | ALLOW_MASK_KEYS;
 
 
 class LLKeyBindResponderInterface
@@ -68,7 +68,7 @@ public:
 
     // Wrapper around recordAndHandleKey
     // It does not record, it handles, but handleKey function is already in use
-    static bool recordKey(KEY key, MASK mask);
+    static bool recordKey(KEY key, MASK mask, BOOL down);
 
     BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down);
     static void onCancel(void* user_data);
@@ -79,7 +79,7 @@ public:
     class Updater;
 
 private:
-    bool recordAndHandleKey(KEY key, MASK mask);
+    bool recordAndHandleKey(KEY key, MASK mask, BOOL down);
     void setKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes);
     LLKeyBindResponderInterface *pParent;
     LLCheckBoxCtrl *pCheckBox;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 93f8cce5c7..9c1aa772d8 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2695,6 +2695,13 @@ void LLViewerWindow::draw()
 // Takes a single keyup event, usually when UI is visible
 BOOL LLViewerWindow::handleKeyUp(KEY key, MASK mask)
 {
+    if (LLSetKeyBindDialog::recordKey(key, mask, FALSE))
+    {
+        LL_DEBUGS() << "KeyUp handled by LLSetKeyBindDialog" << LL_ENDL;
+        LLViewerEventRecorder::instance().logKeyEvent(key, mask);
+        return TRUE;
+    }
+
     LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
 
     if (keyboard_focus
@@ -2738,8 +2745,9 @@ 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))
+    // Menus get handled on key down instead of key up
+    // so keybindings have to be recorded before that
+    if (LLSetKeyBindDialog::recordKey(key, mask, TRUE))
     {
         LL_DEBUGS() << "Key handled by LLSetKeyBindDialog" << LL_ENDL;
         LLViewerEventRecorder::instance().logKeyEvent(key,mask);
-- 
cgit v1.2.3


From 65d661bc67a1ea712a8311fa474cf222f2bd3504 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 3 Dec 2020 13:26:44 +0200
Subject: SL-6109 Crash fix for left right selection shift when nothing or
 whole string is selected

---
 indra/llui/llscrolllistctrl.cpp | 62 ++++++++++++++++++++++-------------------
 1 file changed, 34 insertions(+), 28 deletions(-)

(limited to 'indra')

diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 208fc0a219..7d4661c6c7 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -2226,22 +2226,25 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask )
                 {
                     // TODO: support multi-select
                     LLScrollListItem *item = getFirstSelected();
-                    S32 cell = item->getSelectedCell();
-                    switch (mSelectionType)
+                    if (item)
                     {
-                    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;
+                        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;
                     }
-                    item->setSelectedCell(cell);
-                    handled = TRUE;
                 }
                 break;
             case KEY_RIGHT:
@@ -2249,22 +2252,25 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask )
                 {
                     // TODO: support multi-select
                     LLScrollListItem *item = getFirstSelected();
-                    S32 cell = item->getSelectedCell();
-                    switch (mSelectionType)
+                    if (item)
                     {
-                    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;
+                        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;
                     }
-                    item->setSelectedCell(cell);
-                    handled = TRUE;
                 }
                 break;
 			case KEY_PAGE_UP:
-- 
cgit v1.2.3


From 99daebb1de59767c87fdfb063e01d0128d164e9c Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Thu, 3 Dec 2020 15:20:50 +0200
Subject: SL-14456 FIXED Stop Moving action does not work in the custom key
 mappings viewer

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

(limited to 'indra')

diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index ad4b9d4215..3954d4fb5e 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -609,7 +609,8 @@ bool edit_avatar_move_backward( EKeystate s )
 
 bool stop_moving( EKeystate s )
 {
-	if( KEYSTATE_DOWN != s  ) return true;
+	//it's supposed that 'stop moving' key will be held down for some time
+	if( KEYSTATE_UP == s  ) return true;
 	// stop agent
 	gAgent.setControlFlags(AGENT_CONTROL_STOP);
 
-- 
cgit v1.2.3


From 4de5f6a8533174696211fab8952adc7001357ba4 Mon Sep 17 00:00:00 2001
From: Mnikolenko Productengine <mnikolenko@productengine.com>
Date: Thu, 3 Dec 2020 17:10:50 +0200
Subject: SL-14455 FIXED Drag ground to turn is still active when Single click
 on land is set to No action

---
 indra/newview/lltoolpie.cpp     |  5 ++++-
 indra/newview/llviewerinput.cpp | 11 +++++++++++
 indra/newview/llviewerinput.h   |  2 ++
 3 files changed, 17 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 85d79bb045..322d0bc727 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -63,6 +63,7 @@
 #include "llviewerobject.h"
 #include "llviewerparcelmgr.h"
 #include "llviewerwindow.h"
+#include "llviewerinput.h"
 #include "llviewermedia.h"
 #include "llvoavatarself.h"
 #include "llviewermediafocus.h"
@@ -743,7 +744,9 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
 		LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL;
 	}
 	else if (!mMouseOutsideSlop 
-		&& mMouseButtonDown)
+		&& mMouseButtonDown
+		// disable camera steering if click on land is not used for moving
+		&& gViewerInput.isMouseBindUsed(CLICK_LEFT))
 	{
 		S32 delta_x = x - mMouseDownX;
 		S32 delta_y = y - mMouseDownY;
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index 3954d4fb5e..c0eaa88f54 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -1527,3 +1527,14 @@ void LLViewerInput::scanMouse()
         }
     }
 }
+
+bool LLViewerInput::isMouseBindUsed(const EMouseClickType mouse, const MASK mask, const S32 mode)
+{
+    S32 size = mMouseBindings[mode].size();
+    for (S32 index = 0; index < size; index++)
+    {
+        if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask)
+            return true;
+    }
+    return false;
+}
diff --git a/indra/newview/llviewerinput.h b/indra/newview/llviewerinput.h
index 1fe55bd585..281a209896 100644
--- a/indra/newview/llviewerinput.h
+++ b/indra/newview/llviewerinput.h
@@ -124,6 +124,8 @@ public:
     BOOL            handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down);
     void            scanMouse();
 
+    bool            isMouseBindUsed(const EMouseClickType mouse, const MASK mask = MASK_NONE, const S32 mode = MODE_THIRD_PERSON);
+
 private:
     bool            scanKey(const std::vector<LLKeyboardBinding> &binding,
                             S32 binding_count,
-- 
cgit v1.2.3


From c713b953e831172bf161d011dc7eda600eb5b139 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 4 Dec 2020 21:25:34 +0200
Subject: SL-14438 Adjusted behavior of recording mask keys

If 'mask+key' got rejected, don record it as 'mask'
---
 indra/newview/llsetkeybinddialog.cpp | 13 +++++++++++--
 indra/newview/llsetkeybinddialog.h   |  1 +
 2 files changed, 12 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp
index a7f005ec19..4b36822e9a 100644
--- a/indra/newview/llsetkeybinddialog.cpp
+++ b/indra/newview/llsetkeybinddialog.cpp
@@ -72,6 +72,7 @@ LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key)
     pParent(NULL),
     mKeyFilterMask(DEFAULT_KEY_FILTER),
     pUpdater(NULL),
+    mLastMaskKey(0),
     mContextConeOpacity(0.f),
     mContextConeInAlpha(0.f),
     mContextConeOutAlpha(0.f),
@@ -211,15 +212,22 @@ bool LLSetKeyBindDialog::recordAndHandleKey(KEY key, MASK mask, BOOL down)
     if (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT)
     {
         // Mask keys get special treatment
+        if ((mKeyFilterMask & ALLOW_MASKS) == 0)
+        {
+            // Masks by themself are not allowed
+            return false;
+        }
         if (down == TRUE)
         {
             // Most keys are handled on 'down' event because menu is handled on 'down'
             // masks are exceptions to let other keys be handled
+            mLastMaskKey = key;
             return false;
         }
-        if ((mKeyFilterMask & ALLOW_MASKS) == 0)
+        if (mLastMaskKey != key)
         {
-            // Mask by themself are not allowed
+            // This was mask+key combination that got rejected, don't handle mask's key
+            // Or user did something like: press shift, press ctrl, release shift
             return false;
         }
         // Mask up event often generates things like 'shift key + shift mask', filter it out.
@@ -251,6 +259,7 @@ bool LLSetKeyBindDialog::recordAndHandleKey(KEY key, MASK mask, BOOL down)
     {
         pDesription->setText(getString("reserved_by_menu"));
         pDesription->setTextArg("[KEYSTR]", LLKeyboard::stringFromAccelerator(mask,key));
+        mLastMaskKey = 0;
         return true;
     }
 
diff --git a/indra/newview/llsetkeybinddialog.h b/indra/newview/llsetkeybinddialog.h
index ec3c813a66..a34b952233 100644
--- a/indra/newview/llsetkeybinddialog.h
+++ b/indra/newview/llsetkeybinddialog.h
@@ -87,6 +87,7 @@ private:
 
     U32 mKeyFilterMask;
     Updater *pUpdater;
+    KEY mLastMaskKey;
 
     static bool sRecordKeys; // for convinience and not to check instance each time
 
-- 
cgit v1.2.3


From 958991ec4d0fa0e51f1410928de5b0d21f1720fb Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 26 Jan 2021 23:26:11 +0200
Subject: SL-14651 Keybinding's panel combobox can cause confusion

---
 .../skins/default/xui/en/panel_preferences_controls.xml        | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

(limited to 'indra')

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 904387909e..9dab7d34e6 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
@@ -15,22 +15,22 @@
    top="6"
    left="10"
    height="23"
-   width="140"
+   width="232"
    name="key_mode">
     <combo_box.item
-     label="Third Person "
+     label="When in third person"
      name="third_person"
      value="1"/>
     <combo_box.item
-     label="First Person (Mouselook)"
+     label="When in first person mode (Mouselook)"
      name="first_person"
      value="0"/>
     <combo_box.item
-     label="Edit Avatar"
+     label="When editing avatar"
      name="edit_avatar"
      value="2"/>
     <combo_box.item
-     label="Sitting"
+     label="When sitting"
      name="sitting"
      value="3"/>
   </combo_box>
-- 
cgit v1.2.3


From abdfc65f56bdf5bba7977760c57b5c7de7a61931 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 27 Jan 2021 18:47:54 +0200
Subject: SL-14424 Remove shortcut that conflicts with camera controls

---
 indra/newview/skins/default/xui/en/menu_viewer.xml | 17 +----------------
 1 file changed, 1 insertion(+), 16 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 47c4a9593d..a59a71a0eb 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -622,8 +622,7 @@
           <menu_item_separator />
           <menu_item_check
              label="Advanced Menu"
-             name="Show Advanced Menu"
-             shortcut="control|alt|shift|D">
+             name="Show Advanced Menu">
             <on_check
                function="CheckControl"
                parameter="UseDebugMenus" />
@@ -2001,20 +2000,6 @@ function="World.EnvPreset"
          name="Shortcuts"
          tear_off="true"
          visible="false">
-            <!-- This second, alternative shortcut for Show Advanced Menu is for backward compatibility.  The main shortcut has been changed so it's Linux-friendly, where the old shortcut is typically eaten by the window manager. -->
-            <menu_item_check
-               label="Show Advanced Menu - legacy shortcut"
-               name="Show Advanced Menu - legacy shortcut"
-               shortcut="control|alt|D">
-              <on_check
-                 function="CheckControl"
-                 parameter="UseDebugMenus" />
-              <on_click
-                 function="ToggleControl"
-                 parameter="UseDebugMenus" />
-            </menu_item_check>
-
-            <menu_item_separator/>
 
             <menu_item_call
              label="Close Window"
-- 
cgit v1.2.3


From d3169aa696f5afaff18eb4d90c8b70a4f5528eb7 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 27 Jan 2021 19:18:22 +0200
Subject: SL-14423 Ctrl+Alt+Shift+A is assigned to 2 things

Remapped debugging avatar textures (requires godlike agent) to Ctrl+Shift+Alt+K
---
 indra/newview/skins/default/xui/en/menu_viewer.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index a59a71a0eb..0a50ff089f 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -3625,7 +3625,7 @@ function="World.EnvPreset"
             <menu_item_call
              label="Debug Avatar Textures"
              name="Debug Avatar Textures"
-             shortcut="control|alt|shift|A">
+             shortcut="control|alt|shift|K">
                 <menu_item_call.on_click
                  function="Advanced.DebugAvatarTextures" />
             </menu_item_call>
-- 
cgit v1.2.3


From 9fc1b51ae85cbb1a25f4058c0866d29f99724183 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Mon, 22 Mar 2021 23:45:25 +0200
Subject: SL-14993 Crash accessing mInvBindMatrix

---
 indra/llprimitive/llmodel.cpp    | 30 +++++++++++++++++++-----------
 indra/newview/llskinningutil.cpp | 34 +++-------------------------------
 indra/newview/llskinningutil.h   |  1 -
 3 files changed, 22 insertions(+), 43 deletions(-)

(limited to 'indra')

diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index a2d9b4cd9b..702a1b5238 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -434,7 +434,7 @@ void LLModel::generateNormals(F32 angle_cutoff)
 
 		if (vol_face.mNumIndices > 65535)
 		{
-			LL_WARNS() << "Too many vertices for normal generation to work." << LL_ENDL;
+			LL_WARNS("MESHSKININFO") << "Too many vertices for normal generation to work." << LL_ENDL;
 			continue;
 		}
 
@@ -1100,7 +1100,7 @@ bool LLModel::loadModel(std::istream& is)
 	{
 		if (!LLSDSerialize::fromBinary(header, is, 1024*1024*1024))
 		{
-			LL_WARNS() << "Mesh header parse error.  Not a valid mesh asset!" << LL_ENDL;
+			LL_WARNS("MESHSKININFO") << "Mesh header parse error.  Not a valid mesh asset!" << LL_ENDL;
 			return false;
 		}
 	}
@@ -1132,7 +1132,7 @@ bool LLModel::loadModel(std::istream& is)
 	if (header[lod_name[lod]]["offset"].asInteger() == -1 || 
 		header[lod_name[lod]]["size"].asInteger() == 0 )
 	{ //cannot load requested LOD
-		LL_WARNS() << "LoD data is invalid!" << LL_ENDL;
+		LL_WARNS("MESHSKININFO") << "LoD data is invalid!" << LL_ENDL;
 		return false;
 	}
 
@@ -1195,7 +1195,7 @@ bool LLModel::loadModel(std::istream& is)
 	}
 	else
 	{
-		LL_WARNS() << "unpackVolumeFaces failed!" << LL_ENDL;
+		LL_WARNS("MESHSKININFO") << "unpackVolumeFaces failed!" << LL_ENDL;
 	}
 
 	return false;
@@ -1223,7 +1223,7 @@ bool LLModel::isMaterialListSubset( LLModel* ref )
 
 		if (!foundRef)
 		{
-            LL_INFOS() << "Could not find material " << mMaterialList[src] << " in reference model " << ref->mLabel << LL_ENDL;
+            LL_INFOS("MESHSKININFO") << "Could not find material " << mMaterialList[src] << " in reference model " << ref->mLabel << LL_ENDL;
 			return false;
 		}
 	}
@@ -1259,7 +1259,7 @@ bool LLModel::matchMaterialOrder(LLModel* ref, int& refFaceCnt, int& modelFaceCn
 	bool isASubset = isMaterialListSubset( ref );
 	if ( !isASubset )
 	{
-		LL_INFOS()<<"Material of model is not a subset of reference."<<LL_ENDL;
+		LL_INFOS("MESHSKININFO")<<"Material of model is not a subset of reference."<<LL_ENDL;
 		return false;
 	}
 	
@@ -1398,6 +1398,14 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin)
 
 			mInvBindMatrix.push_back(mat);
 		}
+
+        if (mJointNames.size() != mInvBindMatrix.size())
+        {
+            LL_WARNS("MESHSKININFO") << "Joints vs bind matrix count mismatch. Dropping joint bindings." << LL_ENDL;
+            mJointNames.clear();
+            mJointNums.clear();
+            mInvBindMatrix.clear();
+        }
 	}
 
 	if (skin.has("bind_shape_matrix"))
@@ -1842,14 +1850,14 @@ bool validate_face(const LLVolumeFace& face)
 	{
 		if (face.mIndices[i] >= face.mNumVertices)
 		{
-			LL_WARNS() << "Face has invalid index." << LL_ENDL;
+			LL_WARNS("MESHSKININFO") << "Face has invalid index." << LL_ENDL;
 			return false;
 		}
 	}
 
 	if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0)
 	{
-		LL_WARNS() << "Face has invalid number of indices." << LL_ENDL;
+		LL_WARNS("MESHSKININFO") << "Face has invalid number of indices." << LL_ENDL;
 		return false;
 	}
 
@@ -1879,7 +1887,7 @@ bool validate_model(const LLModel* mdl)
 {
 	if (mdl->getNumVolumeFaces() == 0)
 	{
-		LL_WARNS() << "Model has no faces!" << LL_ENDL;
+		LL_WARNS("MESHSKININFO") << "Model has no faces!" << LL_ENDL;
 		return false;
 	}
 
@@ -1887,13 +1895,13 @@ bool validate_model(const LLModel* mdl)
 	{
 		if (mdl->getVolumeFace(i).mNumVertices == 0)
 		{
-			LL_WARNS() << "Face has no vertices." << LL_ENDL;
+			LL_WARNS("MESHSKININFO") << "Face has no vertices." << LL_ENDL;
 			return false;
 		}
 
 		if (mdl->getVolumeFace(i).mNumIndices == 0)
 		{
-			LL_WARNS() << "Face has no indices." << LL_ENDL;
+			LL_WARNS("MESHSKININFO") << "Face has no indices." << LL_ENDL;
 			return false;
 		}
 
diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp
index 1fb63c7444..f325315933 100644
--- a/indra/newview/llskinningutil.cpp
+++ b/indra/newview/llskinningutil.cpp
@@ -309,7 +309,8 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a
     if (vol_face.mJointRiggingInfoTab.needsUpdate())
     {
         S32 num_verts = vol_face.mNumVertices;
-        if (num_verts>0 && vol_face.mWeights && (skin->mJointNames.size()>0))
+        S32 num_joints = skin->mJointNames.size();
+        if (num_verts > 0 && vol_face.mWeights && num_joints > 0)
         {
             initJointNums(const_cast<LLMeshSkinInfo*>(skin), avatar);
             if (vol_face.mJointRiggingInfoTab.size()==0)
@@ -343,7 +344,7 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a
                     for (U32 k=0; k<4; ++k)
                     {
 						S32 joint_index = idx[k];
-                        if (wght[k] > 0.0f)
+                        if (wght[k] > 0.0f && num_joints > joint_index)
                         {
                             S32 joint_num = skin->mJointNums[joint_index];
                             if (joint_num >= 0 && joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS)
@@ -394,35 +395,6 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a
     }
 }
 
-void LLSkinningUtil::updateRiggingInfo_(LLMeshSkinInfo* skin, LLVOAvatar *avatar, S32 num_verts, LLVector4a* weights, LLVector4a* positions, U8* joint_indices, LLJointRiggingInfoTab &rig_info_tab)
-{
-    LL_RECORD_BLOCK_TIME(FTM_FACE_RIGGING_INFO);
-    for (S32 i=0; i < num_verts; i++)
-    {
-        LLVector4a& pos  = positions[i];
-        LLVector4a& wght = weights[i];
-        for (U32 k=0; k<4; ++k)
-        {
-            S32 joint_num = skin->mJointNums[joint_indices[k]];
-            llassert(joint_num >= 0 && joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS);
-            {
-                rig_info_tab[joint_num].setIsRiggedTo(true);
-                LLMatrix4a bind_shape;
-                bind_shape.loadu(skin->mBindShapeMatrix);
-                LLMatrix4a inv_bind;
-                inv_bind.loadu(skin->mInvBindMatrix[joint_indices[k]]);
-                LLMatrix4a mat;
-                matMul(bind_shape, inv_bind, mat);
-                LLVector4a pos_joint_space;
-                mat.affineTransform(pos, pos_joint_space);
-                pos_joint_space.mul(wght[k]);
-                LLVector4a *extents = rig_info_tab[joint_num].getRiggedExtents();
-                update_min_max(extents[0], extents[1], pos_joint_space);
-            }
-        }
-    }
-}
-
 // This is used for extracting rotation from a bind shape matrix that
 // already has scales baked in
 LLQuaternion LLSkinningUtil::getUnscaledQuaternion(const LLMatrix4& mat4)
diff --git a/indra/newview/llskinningutil.h b/indra/newview/llskinningutil.h
index 549aa6a29f..efe7c85997 100644
--- a/indra/newview/llskinningutil.h
+++ b/indra/newview/llskinningutil.h
@@ -67,7 +67,6 @@ namespace LLSkinningUtil
 
     void initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar);
     void updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *avatar, LLVolumeFace& vol_face);
-    void updateRiggingInfo_(LLMeshSkinInfo* skin, LLVOAvatar *avatar, S32 num_verts, LLVector4a* weights, LLVector4a* positions, U8* joint_indices, LLJointRiggingInfoTab &rig_info_tab);
 	LLQuaternion getUnscaledQuaternion(const LLMatrix4& mat4);
 };
 
-- 
cgit v1.2.3


From 167e45e309ebeaccb346b8ca05884b8e10bf05eb Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 1 Apr 2021 13:37:32 -0400
Subject: Increment viewer version to 6.4.18 following promotion of DRTVWR-514

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

(limited to 'indra')

diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index dbe6222fdd..a0b6fce83f 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-6.4.17
+6.4.18
-- 
cgit v1.2.3