From 08969001e25397cc947b5aa027522d3cc7aa8c53 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Wed, 25 Sep 2019 17:54:36 +0300
Subject: [PATCH] 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 +-
 .../default/xui/en/floater_select_key.xml     |  16 +-
 .../xui/en/panel_preferences_controls.xml     |  10 +-
 17 files changed, 813 insertions(+), 211 deletions(-)

diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h
index e763d413e58..ef29e7e5cd2 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 765084bbf65..0eca289d4b5 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 481949f275b..25179a57f30 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 @@ class LL_COMMON_API LLKeyData
     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 @@ class LLKeyBind
     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 63762ab8b86..0a33ee88784 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 be90e623adc..0e43af91df1 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -829,6 +829,17 @@ bool LLAgent::enableFlying()
 	return !sitting;
 }
 
+// static
+bool LLAgent::isSitting()
+{
+    BOOL sitting = FALSE;
+    if (isAgentAvatarValid())
+    {
+        sitting = gAgentAvatarp->isSitting();
+    }
+    return sitting;
+}
+
 void LLAgent::standUp()
 {
 	setControlFlags(AGENT_CONTROL_STAND_UP);
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index 5ba1083d8ef..a5d37ef4969 100644
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -343,6 +343,7 @@ class LLAgent : public LLOldEvents::LLObservable
 	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 d3067456fa7..dde7275e8ef 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1451,6 +1451,7 @@ bool LLAppViewer::doFrame()
 			{
 				joystick->scanJoystick();
 				gKeyboard->scanKeyboard();
+                gViewerKeyboard.scanMouse();
 			}
 
 			// Update state based on messages, user input, object idle.
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 4a4f66db145..9c706a0d3ad 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 @@ class LLSetKeyBindDialog : public LLModalDialog
 	~LLSetKeyBindDialog();
 
 	/*virtual*/ BOOL postBuild();
+	/*virtual*/ void onClose(bool app_quiting);
 
 	void setParent(LLPanelPreferenceControls* parent, U32 key_mask = DEFAULT_KEY_FILTER);
 
@@ -186,18 +187,23 @@ class LLSetKeyBindDialog : public LLModalDialog
 	static void onDefault(void* user_data);
 
 private:
-	LLPanelPreferenceControls* mParent;
+	LLPanelPreferenceControls* pParent;
+	LLCheckBoxCtrl* pCheckBox;
 
 	U32 mKeyMask;
 };
 
 LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key)
   : LLModalDialog(key),
-	mParent(NULL),
+	pParent(NULL),
 	mKeyMask(DEFAULT_KEY_FILTER)
 {
 }
 
+LLSetKeyBindDialog::~LLSetKeyBindDialog()
+{
+}
+
 //virtual
 BOOL LLSetKeyBindDialog::postBuild()
 {
@@ -205,15 +211,24 @@ BOOL LLSetKeyBindDialog::postBuild()
 	childSetAction("Default", onDefault, this);
 	childSetAction("Cancel", onCancel, this);
 	getChild<LLUICtrl>("Cancel")->setFocus(TRUE);
-	
+
+	pCheckBox = getChild<LLCheckBoxCtrl>("ignore_masks");
+
 	gFocusMgr.setKeystrokesOnly(TRUE);
 	
 	return TRUE;
 }
 
+//virtual
+void LLSetKeyBindDialog::onClose(bool app_quiting)
+{
+    pParent = NULL;
+    LLModalDialog::onClose(app_quiting);
+}
+
 void LLSetKeyBindDialog::setParent(LLPanelPreferenceControls* parent, U32 key_mask)
 {
-    mParent = parent;
+    pParent = parent;
     mKeyMask = key_mask;
 
     LLTextBase *text_ctrl = getChild<LLTextBase>("descritption");
@@ -232,10 +247,10 @@ void LLSetKeyBindDialog::setParent(LLPanelPreferenceControls* parent, U32 key_ma
         input += getString("keyboard");
     }
     text_ctrl->setTextArg("[INPUT]", input);
-}
 
-LLSetKeyBindDialog::~LLSetKeyBindDialog()
-{
+    bool can_ignore_masks = (key_mask & CAN_IGNORE_MASKS) != 0;
+    pCheckBox->setVisible(can_ignore_masks);
+    pCheckBox->setValue(false);
 }
 
 BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
@@ -249,10 +264,19 @@ BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
         return true;
     }
 
+    if (key == KEY_DELETE)
+    {
+        if (pParent)
+        {
+            pParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
+        }
+        closeFloater();
+        return true;
+    }
+
     // forbidden keys
     if (key == KEY_NONE
         || key == KEY_RETURN
-        || key == KEY_DELETE
         || key == KEY_BACKSPACE)
     {
         return false;
@@ -275,9 +299,9 @@ BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
         return false;
     }
 
-	else if (mParent)
+	if (pParent)
 	{
-		mParent->onSetKeyBind(CLICK_NONE, key, mask);
+        pParent->onSetKeyBind(CLICK_NONE, key, mask, pCheckBox->getValue().asBoolean());
 	}
 	closeFloater();
 	return result;
@@ -305,9 +329,9 @@ BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClic
         && (clicktype != CLICK_RIGHT || mask != 0) // reassigning menu button is not supported
         && ((mKeyMask & ALLOW_MASK_MOUSE) != 0 || mask == 0))
     {
-        if (mParent)
+        if (pParent)
         {
-            mParent->onSetKeyBind(clicktype, KEY_NONE, mask);
+            pParent->onSetKeyBind(clicktype, KEY_NONE, mask, pCheckBox->getValue().asBoolean());
         }
         result = TRUE;
         closeFloater();
@@ -333,9 +357,9 @@ void LLSetKeyBindDialog::onBlank(void* user_data)
 {
     LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
     // tmp needs 'no key' button
-    if (self->mParent)
+    if (self->pParent)
     {
-        self->mParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE);
+        self->pParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
     }
     self->closeFloater();
 }
@@ -345,9 +369,9 @@ void LLSetKeyBindDialog::onDefault(void* user_data)
 {
     LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data;
     // tmp needs 'no key' button
-    if (self->mParent)
+    if (self->pParent)
     {
-        self->mParent->onDefaultKeyBind();
+        self->pParent->onDefaultKeyBind();
     }
     self->closeFloater();
 }
@@ -2972,6 +2996,23 @@ BOOL LLPanelPreferenceControls::postBuild()
 // Something of a workaround: cells don't handle clicks, so we catch a click, then process it on hover.
 BOOL LLPanelPreferenceControls::handleHover(S32 x, S32 y, MASK mask)
 {
+    /*S32 column = pControlsTable->getColumnIndexFromOffset(x);
+    LLScrollListItem* item = pControlsTable->hitItem(x, y);
+    static LLScrollListCell* last_cell = NULL;
+    if (item && column > 0)
+    {
+        LLScrollListCell* cell = item->getColumn(column);
+        if (cell)
+        {
+            cell->highlightText(0, CHAR_MAX);
+            if (last_cell != NULL && last_cell !=cell)
+            {
+                last_cell->highlightText(0, 0);
+            }
+            last_cell = cell;
+        }
+    }*/
+
     if (mShowKeyDialog)
     {
         if (mEditingIndex > 0 && mConflictHandler[mEditingMode].canAssignControl((LLKeyConflictHandler::EControlTypes)mEditingIndex))
@@ -2983,14 +3024,14 @@ BOOL LLPanelPreferenceControls::handleHover(S32 x, S32 y, MASK mask)
                 LLSetKeyBindDialog* dialog = LLFloaterReg::showTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD(), TRUE);
                 if (dialog)
                 {
-                    if (mConflictHandler[mEditingMode].getLoadedMode() == LLKeyConflictHandler::MODE_GENERAL)
-                    {
+                    /*if (mConflictHandler[mEditingMode].getLoadedMode() == LLKeyConflictHandler::MODE_GENERAL)
+                    {*/
                         dialog->setParent(this, DEFAULT_KEY_FILTER);
-                    }
+                    /*}
                     else
                     {
                         dialog->setParent(this, ALLOW_KEYS | ALLOW_MASK_KEYS);
-                    }
+                    }*/
                 }
             }
         }
@@ -3133,10 +3174,6 @@ void LLPanelPreferenceControls::populateControlTable()
             }
         }
     }
-
-    //temp
-    if (mEditingMode == LLKeyConflictHandler::MODE_GENERAL)
-        pControlsTable->setEnabled(false);
 }
 
 // Just a workaround to not care about first separator before headers (we can start from random header)
@@ -3226,7 +3263,8 @@ void LLPanelPreferenceControls::onModeCommit()
     regenerateControls();
 }
 
-void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask)
+// todo: copy onSetKeyBind to interface and inherit from interface
+void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore_mask)
 {
     LLKeyConflictHandler::EControlTypes control = (LLKeyConflictHandler::EControlTypes)mEditingIndex;
 
@@ -3241,7 +3279,7 @@ void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MAS
     if (item && mEditingColumn > 0)
     {
 
-        mConflictHandler[mEditingMode].registerControl(control, mEditingColumn - 1, click, key, mask);
+        mConflictHandler[mEditingMode].registerControl(control, mEditingColumn - 1, click, key, mask, ignore_mask);
 
         LLScrollListCell *cell = item->getColumn(1);
         cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 0));
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index bce84387ab9..1ac0f076d23 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -310,7 +310,7 @@ class LLPanelPreferenceControls : public LLPanelPreference
 
 	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 0f0129bf686..be0b8fd4ca9 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 79bd9b84381..7890be1e280 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -95,7 +95,6 @@ class LLKeyConflictHandler
         CONTROL_WEAR,
         CONTROL_MOVEMENTS, // Group control, for visual representation
         CONTROL_MOVETO,
-        CONTROL_SIT,
         CONTROL_TELEPORTTO,
         CONTROL_FORWARD,
         CONTROL_BACKWARD,
@@ -108,6 +107,7 @@ class LLKeyConflictHandler
         //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 @@ class LLKeyConflictHandler
         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 @@ class LLKeyConflictHandler
     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 @@ class LLKeyConflictHandler
     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 878810e0dd9..f1a2b037e2e 100644
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -603,12 +603,50 @@ void start_gesture( EKeystate s )
 	}
 }
 
-void toggle_parcel_media(EKeystate s)
+void toggle_run(EKeystate s)
 {
+    if (KEYSTATE_DOWN != s) return;
+    bool run = gAgent.getAlwaysRun();
+    if (run)
+    {
+        gAgent.clearAlwaysRun();
+        gAgent.clearRunning();
+    }
+    else
+    {
+        gAgent.setAlwaysRun();
+        gAgent.setRunning();
+    }
+    gAgent.sendWalkRun(!run);
+}
+
+void toggle_sit(EKeystate s)
+{
+    if (KEYSTATE_DOWN != s) return;
+    if (gAgent.isSitting())
+    {
+        gAgent.standUp();
+    }
+    else
+    {
+        gAgent.sitDown();
+    }
+}
+
+void toggle_pause_media(EKeystate s) // analogue of play/pause button in top bar
+{
+    if (KEYSTATE_DOWN != s) return;
     bool pause = LLViewerMedia::isAnyMediaPlaying();
     LLViewerMedia::setAllMediaPaused(pause);
 }
 
+void toggle_enable_media(EKeystate s)
+{
+    if (KEYSTATE_DOWN != s) return;
+    bool pause = LLViewerMedia::isAnyMediaPlaying() || LLViewerMedia::isAnyMediaShowing();
+    LLViewerMedia::setAllMediaEnabled(!pause);
+}
+
 #define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, ACTION);
 REGISTER_KEYBOARD_ACTION("jump", agent_jump);
 REGISTER_KEYBOARD_ACTION("push_down", agent_push_down);
@@ -650,20 +688,24 @@ REGISTER_KEYBOARD_ACTION("edit_avatar_move_backward", edit_avatar_move_backward)
 REGISTER_KEYBOARD_ACTION("stop_moving", stop_moving);
 REGISTER_KEYBOARD_ACTION("start_chat", start_chat);
 REGISTER_KEYBOARD_ACTION("start_gesture", start_gesture);
-REGISTER_KEYBOARD_ACTION("toggle_parcel_media", toggle_parcel_media);
+REGISTER_KEYBOARD_ACTION("toggle_run", toggle_run);
+REGISTER_KEYBOARD_ACTION("toggle_sit", toggle_sit);
+REGISTER_KEYBOARD_ACTION("toggle_pause_media", toggle_pause_media);
+REGISTER_KEYBOARD_ACTION("toggle_enable_media", toggle_enable_media);
 #undef REGISTER_KEYBOARD_ACTION
 
 LLViewerKeyboard::LLViewerKeyboard()
 {
-	for (S32 i = 0; i < MODE_COUNT; i++)
-	{
-		mBindingCount[i] = 0;
-	}
+    resetBindings();
 
 	for (S32 i = 0; i < KEY_COUNT; i++)
 	{
 		mKeyHandledByUI[i] = FALSE;
-	}
+    }
+    for (S32 i = 0; i < CLICK_COUNT; i++)
+    {
+        mMouseLevel[i] = MOUSE_STATE_SILENT;
+    }
 	// we want the UI to never see these keys so that they can always control the avatar/camera
 	for(KEY k = KEY_PAD_UP; k <= KEY_PAD_DIVIDE; k++) 
 	{
@@ -671,7 +713,7 @@ LLViewerKeyboard::LLViewerKeyboard()
 	}
 }
 
-BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode)
+BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode) const
 {
 	if (string == "FIRST_PERSON")
 	{
@@ -705,6 +747,40 @@ BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode)
 	}
 }
 
+BOOL LLViewerKeyboard::mouseFromString(const std::string& string, EMouseClickType *mode) const
+{
+    if (string == "LMB")
+    {
+        *mode = CLICK_LEFT;
+        return TRUE;
+    }
+    else if (string == "DLMB")
+    {
+        *mode = CLICK_DOUBLELEFT;
+        return TRUE;
+    }
+    else if (string == "MMB")
+    {
+        *mode = CLICK_MIDDLE;
+        return TRUE;
+    }
+    else if (string == "MB4")
+    {
+        *mode = CLICK_BUTTON4;
+        return TRUE;
+    }
+    else if (string == "MB5")
+    {
+        *mode = CLICK_BUTTON5;
+        return TRUE;
+    }
+    else
+    {
+        *mode = CLICK_NONE;
+        return FALSE;
+    }
+}
+
 BOOL LLViewerKeyboard::handleKey(KEY translated_key,  MASK translated_mask, BOOL repeated)
 {
 	// check for re-map
@@ -748,7 +824,7 @@ BOOL LLViewerKeyboard::handleKeyUp(KEY translated_key, MASK translated_mask)
 	return gViewerWindow->handleKeyUp(translated_key, translated_mask);
 }
 
-BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name)
+BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const bool ignore, const std::string& function_name)
 {
 	S32 index;
 	typedef boost::function<void(EKeystate)> function_t;
@@ -789,11 +865,22 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c
 	}
 
 	// check for duplicate first and overwrite
-	for (index = 0; index < mBindingCount[mode]; index++)
-	{
-		if (key == mBindings[mode][index].mKey && mask == mBindings[mode][index].mMask)
-			break;
-	}
+    if (ignore)
+    {
+        for (index = 0; index < mKeyIgnoreMaskCount[mode]; index++)
+        {
+            if (key == mKeyIgnoreMask[mode][index].mKey)
+                break;
+        }
+    }
+    else
+    {
+        for (index = 0; index < mKeyBindingCount[mode]; index++)
+        {
+            if (key == mKeyBindings[mode][index].mKey && mask == mKeyBindings[mode][index].mMask)
+                break;
+        }
+    }
 
 	if (index >= MAX_KEY_BINDINGS)
 	{
@@ -807,20 +894,102 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c
 		return FALSE;
 	}
 
-	mBindings[mode][index].mKey = key;
-	mBindings[mode][index].mMask = mask;
-	mBindings[mode][index].mFunction = function;
+    if (ignore)
+    {
+        mKeyIgnoreMask[mode][index].mKey = key;
+        mKeyIgnoreMask[mode][index].mFunction = function;
+
+        if (index == mKeyIgnoreMaskCount[mode])
+            mKeyIgnoreMaskCount[mode]++;
+    }
+    else
+    {
+        mKeyBindings[mode][index].mKey = key;
+        mKeyBindings[mode][index].mMask = mask;
+        mKeyBindings[mode][index].mFunction = function;
 
-	if (index == mBindingCount[mode])
-        mBindingCount[mode]++;
+        if (index == mKeyBindingCount[mode])
+            mKeyBindingCount[mode]++;
+    }
 
 	return TRUE;
 }
 
+BOOL LLViewerKeyboard::bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const bool ignore, const std::string& function_name)
+{
+    S32 index;
+    typedef boost::function<void(EKeystate)> function_t;
+    function_t function = NULL;
+
+    function_t* result = LLKeyboardActionRegistry::getValue(function_name);
+    if (result)
+    {
+        function = *result;
+    }
+
+    if (!function)
+    {
+        LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
+        return FALSE;
+    }
+
+    // check for duplicate first and overwrite
+    if (ignore)
+    {
+        for (index = 0; index < mMouseIgnoreMaskCount[mode]; index++)
+        {
+            if (mouse == mMouseIgnoreMask[mode][index].mMouse)
+                break;
+        }
+    }
+    else
+    {
+        for (index = 0; index < mMouseBindingCount[mode]; index++)
+        {
+            if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask)
+                break;
+        }
+    }
+
+    if (index >= MAX_KEY_BINDINGS)
+    {
+        LL_ERRS() << "LLKeyboard::bindKey() - too many keys for mode " << mode << LL_ENDL;
+        return FALSE;
+    }
+
+    if (mode >= MODE_COUNT)
+    {
+        LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
+        return FALSE;
+    }
+
+    if (ignore)
+    {
+        mMouseIgnoreMask[mode][index].mMouse = mouse;
+        mMouseIgnoreMask[mode][index].mFunction = function;
+
+        if (index == mMouseIgnoreMaskCount[mode])
+            mMouseIgnoreMaskCount[mode]++;
+    }
+    else
+    {
+        mMouseBindings[mode][index].mMouse = mouse;
+        mMouseBindings[mode][index].mMask = mask;
+        mMouseBindings[mode][index].mFunction = function;
+
+        if (index == mMouseBindingCount[mode])
+            mMouseBindingCount[mode]++;
+    }
+
+    return TRUE;
+}
+
 LLViewerKeyboard::KeyBinding::KeyBinding()
 :	key("key"),
+	mouse("mouse"),
 	mask("mask"),
-	command("command")
+	command("command"),
+	ignore("ignore", false)
 {}
 
 LLViewerKeyboard::KeyMode::KeyMode()
@@ -835,12 +1004,20 @@ LLViewerKeyboard::Keys::Keys()
 	edit_avatar("edit_avatar")
 {}
 
+void LLViewerKeyboard::resetBindings()
+{
+    for (S32 i = 0; i < MODE_COUNT; i++)
+    {
+        mKeyBindingCount[i] = 0;
+        mKeyIgnoreMaskCount[i] = 0;
+        mMouseBindingCount[i] = 0;
+        mMouseIgnoreMaskCount[i] = 0;
+    }
+}
+
 S32 LLViewerKeyboard::loadBindingsXML(const std::string& filename)
 {
-	for (S32 i = 0; i < MODE_COUNT; i++)
-	{
-		mBindingCount[i] = 0;
-	}
+    resetBindings();
 
 	S32 binding_count = 0;
 	Keys keys;
@@ -870,9 +1047,20 @@ S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode,
         {
             KEY key;
             MASK mask;
+            bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;
             LLKeyboard::keyFromString(it->key, &key);
             LLKeyboard::maskFromString(it->mask, &mask);
-            bindKey(mode, key, mask, it->command);
+            bindKey(mode, key, mask, ignore, it->command);
+            binding_count++;
+        }
+        else if (it->mouse.isProvided() && !it->mouse.getValue().empty())
+        {
+            EMouseClickType mouse;
+            MASK mask;
+            bool ignore = it->ignore.isProvided() ? it->ignore.getValue() : false;
+            mouseFromString(it->mouse.getValue(), &mouse);
+            LLKeyboard::maskFromString(it->mask, &mask);
+            bindMouse(mode, mouse, mask, ignore, it->command);
             binding_count++;
         }
 	}
@@ -964,7 +1152,7 @@ S32 LLViewerKeyboard::loadBindings(const std::string& filename)
 		}
 
 		// bind key
-		if (bindKey(mode, key, mask, function_string))
+		if (bindKey(mode, key, mask, false, function_string))
 		{
 			binding_count++;
 		}
@@ -976,7 +1164,7 @@ S32 LLViewerKeyboard::loadBindings(const std::string& filename)
 }
 
 
-EKeyboardMode LLViewerKeyboard::getMode()
+EKeyboardMode LLViewerKeyboard::getMode() const
 {
 	if ( gAgentCamera.cameraMouselook() )
 	{
@@ -996,56 +1184,184 @@ EKeyboardMode LLViewerKeyboard::getMode()
 	}
 }
 
-
-// Called from scanKeyboard.
-void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
+bool LLViewerKeyboard::scanKey(const LLKeyboardBinding* binding,
+                               S32 binding_count,
+                               KEY key,
+                               MASK mask,
+                               BOOL key_down,
+                               BOOL key_up,
+                               BOOL key_level,
+                               bool repeat) const
 {
-	if (LLApp::isExiting())
-	{
-		return;
-	}
-
-	S32 mode = getMode();
-	// Consider keyboard scanning as NOT mouse event. JC
-	MASK mask = gKeyboard->currentMask(FALSE);
-
-	LLKeyBinding* binding = mBindings[mode];
-	S32 binding_count = mBindingCount[mode];
-
-
-	if (mKeyHandledByUI[key])
-	{
-		return;
-	}
-
-	// don't process key down on repeated keys
-	BOOL repeat = gKeyboard->getKeyRepeated(key);
-
 	for (S32 i = 0; i < binding_count; i++)
 	{
-		//for (S32 key = 0; key < KEY_COUNT; key++)
 		if (binding[i].mKey == key)
 		{
-			//if (binding[i].mKey == key && binding[i].mMask == mask)
 			if (binding[i].mMask == mask)
 			{
 				if (key_down && !repeat)
 				{
 					// ...key went down this frame, call function
 					binding[i].mFunction( KEYSTATE_DOWN );
+					return true;
 				}
 				else if (key_up)
 				{
 					// ...key went down this frame, call function
 					binding[i].mFunction( KEYSTATE_UP );
+					return true;
 				}
 				else if (key_level)
 				{
 					// ...key held down from previous frame
 					// Not windows, just call the function.
 					binding[i].mFunction( KEYSTATE_LEVEL );
+					return true;
 				}//if
+				// Key+Mask combinations are supposed to be unique, so we won't find anything else
+				return false;
 			}//if
-		}//for
+		}//if
 	}//for
+	return false;
+}
+
+// Called from scanKeyboard.
+void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) const
+{
+	if (LLApp::isExiting())
+	{
+		return;
+	}
+
+	S32 mode = getMode();
+	// Consider keyboard scanning as NOT mouse event. JC
+	MASK mask = gKeyboard->currentMask(FALSE);
+
+	if (mKeyHandledByUI[key])
+	{
+		return;
+	}
+
+	// don't process key down on repeated keys
+	BOOL repeat = gKeyboard->getKeyRepeated(key);
+
+    if (scanKey(mKeyBindings[mode], mKeyBindingCount[mode], key, mask, key_down, key_up, key_level, repeat))
+    {
+        // Nothing found, try ignore list
+        scanKey(mKeyIgnoreMask[mode], mKeyIgnoreMaskCount[mode], key, MASK_NONE, key_down, key_up, key_level, repeat);
+    }
+}
+
+BOOL LLViewerKeyboard::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down)
+{
+    BOOL handled = gViewerWindow->handleAnyMouseClick(window_impl, pos, mask, clicktype, down);
+
+    if (clicktype != CLICK_NONE)
+    {
+        // special case
+        // if UI doesn't handle double click, LMB click is issued, so supres LMB 'down' when doubleclick is set
+        // handle !down as if we are handling doubleclick
+        bool override_lmb = (clicktype == CLICK_LEFT
+            && (mMouseLevel[CLICK_DOUBLELEFT] == MOUSE_STATE_DOWN || mMouseLevel[CLICK_DOUBLELEFT] == MOUSE_STATE_LEVEL));
+
+        if (override_lmb && !down)
+        {
+            // process doubleclick instead
+            clicktype = CLICK_DOUBLELEFT;
+        }
+
+        if (override_lmb && down)
+        {
+            // else-supress
+        }
+        // if UI handled 'down', it should handle 'up' as well
+        // if we handle 'down' not by UI, then we should handle 'up'/'level' regardless of UI
+        else if (handled && mMouseLevel[clicktype] != MOUSE_STATE_SILENT)
+        {
+            // UI handled new 'down' so iterupt whatever state we were in.
+            mMouseLevel[clicktype] = MOUSE_STATE_UP;
+        }
+        else if (down)
+        {
+            if (mMouseLevel[clicktype] == MOUSE_STATE_DOWN)
+            {
+                // this is repeated hit (mouse does not repeat event until release)
+                // for now treat rapid clicking like mouse being held
+                mMouseLevel[clicktype] = MOUSE_STATE_LEVEL;
+            }
+            else
+            {
+                mMouseLevel[clicktype] = MOUSE_STATE_DOWN;
+            }
+        }
+        else
+        {
+            // Released mouse key
+            mMouseLevel[clicktype] = MOUSE_STATE_UP;
+        }
+    }
+
+    return handled;
+}
+
+bool LLViewerKeyboard::scanMouse(const LLMouseBinding *binding, S32 binding_count, EMouseClickType mouse, MASK mask, EMouseState state) const
+{
+    for (S32 i = 0; i < binding_count; i++)
+    {
+        if (binding[i].mMouse == mouse && binding[i].mMask == mask)
+        {
+            switch (state)
+            {
+            case MOUSE_STATE_DOWN:
+                binding[i].mFunction(KEYSTATE_DOWN);
+                break;
+            case MOUSE_STATE_LEVEL:
+                binding[i].mFunction(KEYSTATE_LEVEL);
+                break;
+            case MOUSE_STATE_UP:
+                binding[i].mFunction(KEYSTATE_UP);
+                break;
+            default:
+                break;
+            }
+            // Key+Mask combinations are supposed to be unique, no need to continue
+            return true;
+        }
+    }
+    return false;
+}
+
+// todo: this recods key, scanMouse() triggers functions with EKeystate
+bool LLViewerKeyboard::scanMouse(EMouseClickType click, EMouseState state) const
+{
+    bool res = false;
+    S32 mode = getMode();
+    MASK mask = gKeyboard->currentMask(TRUE);
+    res = scanMouse(mMouseBindings[mode], mMouseBindingCount[mode], click, mask, state);
+    if (!res)
+    {
+        res = scanMouse(mMouseIgnoreMask[mode], mMouseIgnoreMaskCount[mode], click, MASK_NONE, state);
+    }
+    return res;
+}
+
+void LLViewerKeyboard::scanMouse()
+{
+    for (S32 i = 0; i < CLICK_COUNT; i++)
+    {
+        if (mMouseLevel[i] != MOUSE_STATE_SILENT)
+        {
+            scanMouse((EMouseClickType)i, mMouseLevel[i]);
+            if (mMouseLevel[i] == MOUSE_STATE_DOWN)
+            {
+                // mouse doesn't support 'continued' state like keyboard does, so after handling, switch to LEVEL
+                mMouseLevel[i] = MOUSE_STATE_LEVEL;
+            }
+            else if (mMouseLevel[i] == MOUSE_STATE_UP)
+            {
+                mMouseLevel[i] = MOUSE_STATE_SILENT;
+            }
+        }
+    }
 }
diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h
index 2bfe285be4c..3ba033509c8 100644
--- a/indra/newview/llviewerkeyboard.h
+++ b/indra/newview/llviewerkeyboard.h
@@ -43,6 +43,27 @@ class LLNamedFunction
 	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 @@ class LLViewerKeyboard
 		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 @@ class LLViewerKeyboard
 
 	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 2c582958145..bd5370f07f9 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -898,6 +898,17 @@ LLViewerWindow::Params::Params()
 {}
 
 
+void LLViewerWindow::handlePieMenu(S32 x, S32 y, MASK mask)
+{
+    if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance() && gAgent.isInitialized())
+    {
+        // If the current tool didn't process the click, we should show
+        // the pie menu.  This can be done by passing the event to the pie
+        // menu tool.
+        LLToolPie::getInstance()->handleRightMouseDown(x, y, mask);
+    }
+}
+
 BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down)
 {
 	const char* buttonname = "";
@@ -996,6 +1007,11 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK m
 				LLViewerEventRecorder::instance().logMouseEvent(std::string(buttonstatestr),std::string(buttonname)); 
 
 			}
+			else if (down && clicktype == CLICK_RIGHT)
+			{
+				handlePieMenu(x, y, mask);
+				r = TRUE;
+			}
 			return r;
 		}
 
@@ -1042,7 +1058,12 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK m
 		return TRUE;
 	}
 
-	
+	if (down && clicktype == CLICK_RIGHT)
+	{
+		handlePieMenu(x, y, mask);
+		return TRUE;
+	}
+
 	// If we got this far on a down-click, it wasn't handled.
 	// Up-clicks, though, are always handled as far as the OS is concerned.
 	BOOL default_rtn = !down;
@@ -1061,7 +1082,8 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask
         mMouseDownTimer.reset();
     }    
     BOOL down = TRUE;
-	return handleAnyMouseClick(window, pos, mask, CLICK_LEFT, down);
+    //handleMouse() loops back to LLViewerWindow::handleAnyMouseClick
+    return gViewerKeyboard.handleMouse(window, pos, mask, CLICK_LEFT, down);
 }
 
 BOOL LLViewerWindow::handleDoubleClick(LLWindow *window,  LLCoordGL pos, MASK mask)
@@ -1069,7 +1091,7 @@ BOOL LLViewerWindow::handleDoubleClick(LLWindow *window,  LLCoordGL pos, MASK ma
 	// try handling as a double-click first, then a single-click if that
 	// wasn't handled.
 	BOOL down = TRUE;
-	if (handleAnyMouseClick(window, pos, mask, CLICK_DOUBLELEFT, down))
+	if (gViewerKeyboard.handleMouse(window, pos, mask, CLICK_DOUBLELEFT, down))
 	{
 		return TRUE;
 	}
@@ -1083,46 +1105,24 @@ BOOL LLViewerWindow::handleMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)
         mMouseDownTimer.stop();
     }
     BOOL down = FALSE;
-	return handleAnyMouseClick(window, pos, mask, CLICK_LEFT, down);
+    return gViewerKeyboard.handleMouse(window, pos, mask, CLICK_LEFT, down);
 }
-
-
 BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask)
 {
-	S32 x = pos.mX;
-	S32 y = pos.mY;
-	x = ll_round((F32)x / mDisplayScale.mV[VX]);
-	y = ll_round((F32)y / mDisplayScale.mV[VY]);
-
 	BOOL down = TRUE;
-	BOOL handle = handleAnyMouseClick(window, pos, mask, CLICK_RIGHT, down);
-	if (handle)
-		return handle;
-
-	// *HACK: this should be rolled into the composite tool logic, not
-	// hardcoded at the top level.
-	if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance() && gAgent.isInitialized())
-	{
-		// If the current tool didn't process the click, we should show
-		// the pie menu.  This can be done by passing the event to the pie
-		// menu tool.
-		LLToolPie::getInstance()->handleRightMouseDown(x, y, mask);
-		// show_context_menu( x, y, mask );
-	}
-
-	return TRUE;
+	return gViewerKeyboard.handleMouse(window, pos, mask, CLICK_RIGHT, down);
 }
 
 BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)
 {
 	BOOL down = FALSE;
- 	return handleAnyMouseClick(window, pos, mask, CLICK_RIGHT, down);
+ 	return gViewerKeyboard.handleMouse(window, pos, mask, CLICK_RIGHT, down);
 }
 
 BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask)
 {
 	BOOL down = TRUE;
- 	handleAnyMouseClick(window, pos, mask, CLICK_MIDDLE, down);
+ 	gViewerKeyboard.handleMouse(window, pos, mask, CLICK_MIDDLE, down);
   
   	// Always handled as far as the OS is concerned.
 	return TRUE;
@@ -1277,7 +1277,7 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi
 BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)
 {
 	BOOL down = FALSE;
- 	handleAnyMouseClick(window, pos, mask, CLICK_MIDDLE, down);
+ 	gViewerKeyboard.handleMouse(window, pos, mask, CLICK_MIDDLE, down);
   
   	// Always handled as far as the OS is concerned.
 	return TRUE;
@@ -1288,10 +1288,10 @@ BOOL LLViewerWindow::handleOtherMouse(LLWindow *window, LLCoordGL pos, MASK mask
     switch (button)
     {
     case 4:
-        handleAnyMouseClick(window, pos, mask, CLICK_BUTTON4, down);
+        gViewerKeyboard.handleMouse(window, pos, mask, CLICK_BUTTON4, down);
         break;
     case 5:
-        handleAnyMouseClick(window, pos, mask, CLICK_BUTTON5, down);
+        gViewerKeyboard.handleMouse(window, pos, mask, CLICK_BUTTON5, down);
         break;
     default:
         break;
@@ -1458,7 +1458,8 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key,  MASK mask, BOOL repeated)
     		return FALSE;
 	}
 
-	return gViewerKeyboard.handleKey(key, mask, repeated);
+    // remaps, handles ignored cases and returns back to viewer window.
+    return gViewerKeyboard.handleKey(key, mask, repeated);
 }
 
 BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key,  MASK mask)
@@ -2936,6 +2937,7 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
 	{
 		if (mask != MASK_ALT)
 		{
+			// remaps, handles ignored cases and returns back to viewer window.
 			return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
 		}
 	}
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 5f03685cee9..a6365ab328e 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -175,8 +175,9 @@ class LLViewerWindow : public LLWindowCallbacks
 	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 c00b8059542..32f091938ec 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 1bfee20c81e..0c652845f0c 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
-- 
GitLab