diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp
index 0eca289d4b50439f5ba94d710193ca05ca89a039..ff88a9c9aadb479551e93949f979f7a4c7362957 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 25179a57f3089867f53e787200d33c043012b06a..39cb668aac09baefe8f62ae29b135b83bd10fe9d 100644
--- a/indra/llcommon/llkeybind.h
+++ b/indra/llcommon/llkeybind.h
@@ -74,17 +74,26 @@ 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;
+    // 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 0a33ee8878497ab5a431c7b7b7a88a697fc04eac..d6627a6957f6389da5887464f9f3b9c4966be2b2 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 1604a9b1dcdffbc86952ef791f5d471f03cf2090..b4bb14bcf142b153736b2b713c4f73bc096acbe2 100644
--- a/indra/llui/llscrolllistcell.h
+++ b/indra/llui/llscrolllistcell.h
@@ -103,6 +103,7 @@ class LLScrollListCell
 	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 @@ class LLScrollListText : public LLScrollListCell
 	/*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 da1e87fda47b5e2c69df73332707e1fb34a1d16d..15447e7e83b4419127be0485031fd508b4bfc983 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -8184,7 +8184,7 @@
     <key>PushToTalkButton</key>
     <map>
       <key>Comment</key>
-      <string>Which button or keyboard key is used for push-to-talk</string>
+      <string>(Obsolete)Which button or keyboard key is used for push-to-talk</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index dde7275e8effe4c51bf323e529896f338ad2ce39..97e770a1067e6ec447b97d9026531839ab7a7ebf 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1004,20 +1004,15 @@ bool LLAppViewer::init()
 	gGLManager.getGLInfo(gDebugInfo);
 	gGLManager.printGLInfoString();
 
-	// Load Default bindings
-	std::string key_bindings_file = gDirUtilp->findFile("keys.xml",
-														gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
-														gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
-
-
-	if (!gViewerKeyboard.loadBindingsXML(key_bindings_file))
+	// Load User's bindings
+	std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "keys.xml");
+	if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerKeyboard.loadBindingsXML(key_bindings_file))
 	{
-		std::string key_bindings_file = gDirUtilp->findFile("keys.ini",
-															gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
-															gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
-		if (!gViewerKeyboard.loadBindings(key_bindings_file))
+		// Failed to load custom bindings, try default ones
+		key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "keys.xml");
+		if (!gViewerKeyboard.loadBindingsXML(key_bindings_file))
 		{
-			LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL;
+			LL_ERRS("InitInfo") << "Unable to open default key bindings from" << key_bindings_file << LL_ENDL;
 		}
 	}
 
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 6085c92f49d4078de46499d75ec6cbcd8a798a44..c0e334795abb1774ccfe465199aeaeda1f9b838f 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -222,7 +222,11 @@ BOOL LLSetKeyBindDialog::postBuild()
 //virtual
 void LLSetKeyBindDialog::onClose(bool app_quiting)
 {
-    pParent = NULL;
+    if (pParent)
+    {
+        pParent->onCancelKeyBind();
+        pParent = NULL;
+    }
     LLModalDialog::onClose(app_quiting);
 }
 
@@ -269,6 +273,7 @@ BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
         if (pParent)
         {
             pParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
+            pParent = NULL;
         }
         closeFloater();
         return true;
@@ -302,6 +307,7 @@ BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask)
 	if (pParent)
 	{
         pParent->onSetKeyBind(CLICK_NONE, key, mask, pCheckBox->getValue().asBoolean());
+        pParent = NULL;
 	}
 	closeFloater();
 	return result;
@@ -332,6 +338,7 @@ BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClic
         if (pParent)
         {
             pParent->onSetKeyBind(clicktype, KEY_NONE, mask, pCheckBox->getValue().asBoolean());
+            pParent = NULL;
         }
         result = TRUE;
         closeFloater();
@@ -360,6 +367,7 @@ void LLSetKeyBindDialog::onBlank(void* user_data)
     if (self->pParent)
     {
         self->pParent->onSetKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false);
+        self->pParent = NULL;
     }
     self->closeFloater();
 }
@@ -372,6 +380,7 @@ void LLSetKeyBindDialog::onDefault(void* user_data)
     if (self->pParent)
     {
         self->pParent->onDefaultKeyBind();
+        self->pParent = NULL;
     }
     self->closeFloater();
 }
@@ -2968,11 +2977,12 @@ LLPanelPreferenceControls::LLPanelPreferenceControls()
     mEditingIndex(-1),
     mEditingColumn(-1),
     mEditingMode(0),
-    mShowKeyDialog(false)
+    mShowKeyDialog(false),
+    mHighlightedCell(NULL)
 {
-    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i)
+    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
     {
-        mConflictHandler[i].setLoadMode((LLKeyConflictHandler::EModes)i);
+        mConflictHandler[i].setLoadMode((LLKeyConflictHandler::ESourceMode)i);
     }
 }
 
@@ -3000,46 +3010,34 @@ BOOL LLPanelPreferenceControls::postBuild()
 // Something of a workaround: cells don't handle clicks, so we catch a click, then process it on hover.
 BOOL LLPanelPreferenceControls::handleHover(S32 x, S32 y, MASK mask)
 {
-    /*S32 column = pControlsTable->getColumnIndexFromOffset(x);
-    LLScrollListItem* item = pControlsTable->hitItem(x, y);
-    static LLScrollListCell* last_cell = NULL;
-    if (item && column > 0)
-    {
-        LLScrollListCell* cell = item->getColumn(column);
-        if (cell)
-        {
-            cell->highlightText(0, CHAR_MAX);
-            if (last_cell != NULL && last_cell !=cell)
-            {
-                last_cell->highlightText(0, 0);
-            }
-            last_cell = cell;
-        }
-    }*/
-
     if (mShowKeyDialog)
     {
-        if (mEditingIndex > 0 && mConflictHandler[mEditingMode].canAssignControl((LLKeyConflictHandler::EControlTypes)mEditingIndex))
+        mShowKeyDialog = false;
+        if (mEditingIndex > 0
+            && mConflictHandler[mEditingMode].canAssignControl((LLKeyConflictHandler::EControlTypes)mEditingIndex))
         {
-            mEditingColumn = pControlsTable->getColumnIndexFromOffset(x);
-
-            if (mEditingColumn >0)
+            LLScrollListItem* item = pControlsTable->getFirstSelected(); // don't use pControlsTable->hitItem(x, y) dur to drift;
+            if (item)
             {
-                LLSetKeyBindDialog* dialog = LLFloaterReg::showTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD(), TRUE);
-                if (dialog)
+                mEditingColumn = pControlsTable->getColumnIndexFromOffset(x);
+                if (mEditingColumn > 0)
                 {
-                    /*if (mConflictHandler[mEditingMode].getLoadedMode() == LLKeyConflictHandler::MODE_GENERAL)
-                    {*/
-                        dialog->setParent(this, DEFAULT_KEY_FILTER);
-                    /*}
-                    else
+                    LLScrollListCell* cell = item->getColumn(mEditingColumn);
+                    if (cell)
                     {
-                        dialog->setParent(this, ALLOW_KEYS | ALLOW_MASK_KEYS);
-                    }*/
+                        LLSetKeyBindDialog* dialog = LLFloaterReg::showTypedInstance<LLSetKeyBindDialog>("keybind_dialog", LLSD(), TRUE);
+                        if (dialog)
+                        {
+                            dialog->setParent(this, DEFAULT_KEY_FILTER);
+                            cell->setHighlighted(true);
+                            mHighlightedCell = cell;
+                            pControlsTable->deselectAllItems();
+                            return TRUE;
+                        }
+                    }
                 }
             }
         }
-        mShowKeyDialog = false;
     }
     return LLPanelPreference::handleHover(x, y, mask);
 }
@@ -3089,7 +3087,7 @@ void LLPanelPreferenceControls::addGroupRow(const std::string &icon, S32 index)
 void LLPanelPreferenceControls::regenerateControls()
 {
     mEditingMode = pKeyModeBox->getValue().asInteger();
-    mConflictHandler[mEditingMode].loadFromSettings((LLKeyConflictHandler::EModes)mEditingMode);
+    mConflictHandler[mEditingMode].loadFromSettings((LLKeyConflictHandler::ESourceMode)mEditingMode);
     populateControlTable();
 }
 
@@ -3097,6 +3095,12 @@ void LLPanelPreferenceControls::populateControlTable()
 {
     pControlsTable->clearRows();
 
+    if (mHighlightedCell)
+    {
+        mHighlightedCell->setHighlighted(false);
+        mHighlightedCell = NULL;
+    }
+
     // todo: subsections need sorting?
     std::string label, control_name;
     LLScrollListCell::Params cell_params;
@@ -3189,20 +3193,50 @@ void LLPanelPreferenceControls::addSeparator()
     }
 }
 
+void LLPanelPreferenceControls::updateTable()
+{
+    std::vector<LLScrollListItem*> list = pControlsTable->getAllData();
+    for (S32 i = 0; i < list.size(); ++i)
+    {
+        S32 value = list[i]->getValue().asInteger();
+        if (value > 0)
+        {
+            LLKeyConflictHandler::EControlTypes control = (LLKeyConflictHandler::EControlTypes)value;
+            LLScrollListCell* cell = list[i]->getColumn(1);
+            cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 0));
+            cell = list[i]->getColumn(2);
+            cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 1));
+            cell = list[i]->getColumn(3);
+            cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 2));
+        }
+    }
+
+    if (mHighlightedCell)
+    {
+        mHighlightedCell->setHighlighted(false);
+        mHighlightedCell = NULL;
+    }
+}
+
 void LLPanelPreferenceControls::apply()
 {
-    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i)
+    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
     {
         if (mConflictHandler[i].hasUnsavedChanges())
         {
             mConflictHandler[i].saveToSettings();
         }
     }
+    if (mHighlightedCell)
+    {
+        mHighlightedCell->setHighlighted(false);
+        mHighlightedCell = NULL;
+    }
 }
 
 void LLPanelPreferenceControls::cancel()
 {
-    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i)
+    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
     {
         if (mConflictHandler[i].hasUnsavedChanges())
         {
@@ -3210,11 +3244,16 @@ void LLPanelPreferenceControls::cancel()
         }
     }
     pControlsTable->clear();
+    if (mHighlightedCell)
+    {
+        mHighlightedCell->setHighlighted(false);
+        mHighlightedCell = NULL;
+    }
 }
 
 void LLPanelPreferenceControls::saveSettings()
 {
-    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i)
+    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
     {
         if (mConflictHandler[i].hasUnsavedChanges())
         {
@@ -3227,6 +3266,11 @@ void LLPanelPreferenceControls::saveSettings()
     {
         regenerateControls();
     }
+    else if (mHighlightedCell)
+    {
+        mHighlightedCell->setHighlighted(false);
+        mHighlightedCell = NULL;
+    }
 }
 
 void LLPanelPreferenceControls::resetDirtyChilds()
@@ -3260,6 +3304,12 @@ void LLPanelPreferenceControls::onListCommit()
     // use coordinates from hover to calculate cell
     mEditingIndex = control;
     mShowKeyDialog = true;
+
+    if (mHighlightedCell)
+    {
+        mHighlightedCell->setHighlighted(false);
+        mHighlightedCell = NULL;
+    }
 }
 
 void LLPanelPreferenceControls::onModeCommit()
@@ -3279,30 +3329,20 @@ void LLPanelPreferenceControls::onSetKeyBind(EMouseClickType click, KEY key, MAS
 
     pControlsTable->deselectAllItems();
     pControlsTable->selectByValue(mEditingIndex);
-    LLScrollListItem *item = pControlsTable->getFirstSelected();
-    if (item && mEditingColumn > 0)
+    if ( mEditingColumn > 0)
     {
-
         mConflictHandler[mEditingMode].registerControl(control, mEditingColumn - 1, click, key, mask, ignore_mask);
-
-        LLScrollListCell *cell = item->getColumn(1);
-        cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 0));
-        cell = item->getColumn(2);
-        cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 1));
-        cell = item->getColumn(3);
-        cell->setValue(mConflictHandler[mEditingMode].getControlString(control, 2));
     }
 
-    populateControlTable();
+    updateTable();
 }
 
 void LLPanelPreferenceControls::onRestoreDefaults()
 {
-    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT; ++i)
+    for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)
     {
         mConflictHandler[mEditingMode].resetToDefaults();
     }
-    populateControlTable();
 }
 
 void LLPanelPreferenceControls::onDefaultKeyBind()
@@ -3316,16 +3356,20 @@ void LLPanelPreferenceControls::onDefaultKeyBind()
 
     pControlsTable->deselectAllItems();
     pControlsTable->selectByValue(mEditingIndex);
-    LLScrollListItem *item = pControlsTable->getFirstSelected();
-    if (item)
+
+    if (mEditingColumn > 0)
     {
-        LLScrollListCell *cell = item->getColumn(mEditingColumn);
+        mConflictHandler[mEditingMode].resetToDefault(control, mEditingColumn - 1);
+    }
+    updateTable();
+}
 
-        if (mEditingColumn > 0)
-        {
-            mConflictHandler[mEditingMode].resetToDefault(control, mEditingColumn - 1);
-            cell->setValue(mConflictHandler[mEditingMode].getControlString(control, mEditingColumn - 1));
-        }
+void LLPanelPreferenceControls::onCancelKeyBind()
+{
+    if (mHighlightedCell)
+    {
+        mHighlightedCell->setHighlighted(false);
+        mHighlightedCell = NULL;
     }
 }
 
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 1ac0f076d23a5cf40db8f15c173e03337e3cd1e5..513fda96dfa895664d82e792a4da98af8ea98dab 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -46,6 +46,7 @@ class LLPanelDebug;
 class LLMessageSystem;
 class LLComboBox;
 class LLScrollListCtrl;
+class LLScrollListCell;
 class LLSliderCtrl;
 class LLSD;
 class LLTextBox;
@@ -313,15 +314,18 @@ class LLPanelPreferenceControls : public LLPanelPreference
 	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 87ea408a6a53dfd9232c715700d87cc1352a8be0..66d420369ea1bc9510881402a91f08a32ea87758 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 b0f99e2d0cc46f54572db08ffa464c32aca11698..00fbe18863dcc6e7176906d3284645578d1a68a9 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 @@ class LLKeyConflictHandler
         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 @@ class LLKeyConflictHandler
     // 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 @@ class LLKeyConflictHandler
 
 
     // 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 @@ class LLKeyConflictHandler
     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 e2ab450d8cad8096ad16e2ec62121d573dbd6ec4..5235914c34884c0392c6d78d135e59cbdf706dfd 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 4edfd7fb39f97e10b8c9b39885b6b06a012727b9..dc9c0edc0cf9ce00b56d93caa3b0f96b3ae9d782 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 c1c8718f7d3ac11c7427d62af00adb5524bc0af8..60159594c9d011d8afe4fe35bdf4f8f4f49d76b2 100644
--- a/indra/newview/lltoolpie.h
+++ b/indra/newview/lltoolpie.h
@@ -67,8 +67,8 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie>
 	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 420980ca56b8dcc75bfeaf6d8c4aa2f05fa711fe..9755d3444ae64e84240c34b11d01063a76ac875b 100644
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -26,19 +26,21 @@
 
 #include "llviewerprecompiledheaders.h"
 
+#include "llviewerkeyboard.h"
+
 #include "llappviewer.h"
 #include "llfloaterreg.h"
-#include "llviewerkeyboard.h"
 #include "llmath.h"
 #include "llagent.h"
 #include "llagentcamera.h"
 #include "llfloaterimnearbychat.h"
-#include "llviewercontrol.h"
 #include "llfocusmgr.h"
+#include "llkeybind.h" // LLKeyData
 #include "llmorphview.h"
 #include "llmoveview.h"
 #include "lltoolfocus.h"
 #include "lltoolpie.h"
+#include "llviewercontrol.h"
 #include "llviewerwindow.h"
 #include "llvoavatarself.h"
 #include "llfloatercamera.h"
@@ -55,21 +57,23 @@ const F32 NUDGE_TIME = 0.25f;  // in seconds
 const S32 NUDGE_FRAMES = 2;
 const F32 ORBIT_NUDGE_RATE = 0.05f;  // fraction of normal speed
 
+const LLKeyData agent_control_lbutton(CLICK_LEFT, KEY_NONE, MASK_NONE, true);
+
 struct LLKeyboardActionRegistry 
-:	public LLRegistrySingleton<std::string, boost::function<void (EKeystate keystate)>, LLKeyboardActionRegistry>
+:	public LLRegistrySingleton<std::string, boost::function<bool (EKeystate keystate)>, LLKeyboardActionRegistry>
 {
 	LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry);
 };
 
 LLViewerKeyboard gViewerKeyboard;
 
-void agent_jump( EKeystate s )
+bool agent_jump( EKeystate s )
 {
 	static BOOL first_fly_attempt(TRUE);
 	if (KEYSTATE_UP == s)
 	{
 		first_fly_attempt = TRUE;
-		return;
+		return true;
 	}
 	F32 time = gKeyboard->getCurKeyElapsedTime();
 	S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
@@ -87,12 +91,14 @@ void agent_jump( EKeystate s )
 		first_fly_attempt = FALSE;
 		gAgent.moveUp(1);
 	}
+	return true;
 }
 
-void agent_push_down( EKeystate s )
+bool agent_push_down( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgent.moveUp(-1);
+	return true;
 }
 
 static void agent_check_temporary_run(LLAgent::EDoubleTapRunMode mode)
@@ -152,11 +158,11 @@ static void agent_push_forwardbackward( EKeystate s, S32 direction, LLAgent::EDo
 	}
 }
 
-void camera_move_forward( EKeystate s );
+bool camera_move_forward( EKeystate s );
 
-void agent_push_forward( EKeystate s )
+bool agent_push_forward( EKeystate s )
 {
-	if(gAgent.isMovementLocked()) return;
+	if(gAgent.isMovementLocked()) return true;
 
 	//in free camera control mode we need to intercept keyboard events for avatar movements
 	if (LLFloaterCamera::inFreeCameraMode())
@@ -167,13 +173,14 @@ void agent_push_forward( EKeystate s )
 	{
 		agent_push_forwardbackward(s, 1, LLAgent::DOUBLETAP_FORWARD);
 	}
+	return true;
 }
 
-void camera_move_backward( EKeystate s );
+bool camera_move_backward( EKeystate s );
 
-void agent_push_backward( EKeystate s )
+bool agent_push_backward( EKeystate s )
 {
-	if(gAgent.isMovementLocked()) return;
+	if(gAgent.isMovementLocked()) return true;
 
 	//in free camera control mode we need to intercept keyboard events for avatar movements
 	if (LLFloaterCamera::inFreeCameraMode())
@@ -188,6 +195,7 @@ void agent_push_backward( EKeystate s )
 	{
 		agent_push_forwardbackward(s, -1, LLAgent::DOUBLETAP_BACKWARD);
 	}
+	return true;
 }
 
 static void agent_slide_leftright( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode )
@@ -208,31 +216,33 @@ static void agent_slide_leftright( EKeystate s, S32 direction, LLAgent::EDoubleT
 }
 
 
-void agent_slide_left( EKeystate s )
+bool agent_slide_left( EKeystate s )
 {
-	if(gAgent.isMovementLocked()) return;
+	if(gAgent.isMovementLocked()) return true;
 	agent_slide_leftright(s, 1, LLAgent::DOUBLETAP_SLIDELEFT);
+	return true;
 }
 
 
-void agent_slide_right( EKeystate s )
+bool agent_slide_right( EKeystate s )
 {
-	if(gAgent.isMovementLocked()) return;
+	if(gAgent.isMovementLocked()) return true;
 	agent_slide_leftright(s, -1, LLAgent::DOUBLETAP_SLIDERIGHT);
+	return true;
 }
 
-void camera_spin_around_cw( EKeystate s );
+bool camera_spin_around_cw( EKeystate s );
 
-void agent_turn_left( EKeystate s )
+bool agent_turn_left(EKeystate s)
 {
 	//in free camera control mode we need to intercept keyboard events for avatar movements
 	if (LLFloaterCamera::inFreeCameraMode())
 	{
 		camera_spin_around_cw(s);
-		return;
+		return true;
 	}
 
-	if(gAgent.isMovementLocked()) return;
+	if(gAgent.isMovementLocked()) return false;
 
 	if (LLToolCamera::getInstance()->mouseSteerMode())
 	{
@@ -244,25 +254,26 @@ void agent_turn_left( EKeystate s )
 		{
 			// Check temporary running. In case user released 'left' key with shift already released.
 			agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDELEFT);
-			return;
+			return true;
 		}
 		F32 time = gKeyboard->getCurKeyElapsedTime();
 		gAgent.moveYaw( LLFloaterMove::getYawRate( time ) );
 	}
+	return true;
 }
 
-void camera_spin_around_ccw( EKeystate s );
+bool camera_spin_around_ccw( EKeystate s );
 
-void agent_turn_right( EKeystate s )
+bool agent_turn_right( EKeystate s )
 {
 	//in free camera control mode we need to intercept keyboard events for avatar movements
 	if (LLFloaterCamera::inFreeCameraMode())
 	{
 		camera_spin_around_ccw(s);
-		return;
+		return true;
 	}
 
-	if(gAgent.isMovementLocked()) return;
+	if(gAgent.isMovementLocked()) return false;
 
 	if (LLToolCamera::getInstance()->mouseSteerMode())
 	{
@@ -274,35 +285,39 @@ void agent_turn_right( EKeystate s )
 		{
 			// Check temporary running. In case user released 'right' key with shift already released.
 			agent_check_temporary_run(LLAgent::DOUBLETAP_SLIDERIGHT);
-			return;
+			return true;
 		}
 		F32 time = gKeyboard->getCurKeyElapsedTime();
 		gAgent.moveYaw( -LLFloaterMove::getYawRate( time ) );
 	}
+	return true;
 }
 
-void agent_look_up( EKeystate s )
+bool agent_look_up( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgent.movePitch(-1);
 	//gAgent.rotate(-2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
+	return true;
 }
 
 
-void agent_look_down( EKeystate s )
+bool agent_look_down( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgent.movePitch(1);
 	//gAgent.rotate(2.f * DEG_TO_RAD, gAgent.getFrame().getLeftAxis() );
+	return true;
 }
 
-void agent_toggle_fly( EKeystate s )
+bool agent_toggle_fly( EKeystate s )
 {
 	// Only catch the edge
 	if (KEYSTATE_DOWN == s )
 	{
 		LLAgent::toggleFlying();
 	}
+	return true;
 }
 
 F32 get_orbit_rate()
@@ -320,24 +335,26 @@ F32 get_orbit_rate()
 	}
 }
 
-void camera_spin_around_ccw( EKeystate s )
+bool camera_spin_around_ccw( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
+	return true;
 }
 
 
-void camera_spin_around_cw( EKeystate s )
+bool camera_spin_around_cw( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setOrbitRightKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_spin_around_ccw_sitting( EKeystate s )
+bool camera_spin_around_ccw_sitting( EKeystate s )
 {
-	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT ) return;
+	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDERIGHT ) return true;
 	if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning())
 	{
 		//send keystrokes, but do not change camera
@@ -348,12 +365,13 @@ void camera_spin_around_ccw_sitting( EKeystate s )
 		//change camera but do not send keystrokes
 		gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
 	}
+	return true;
 }
 
 
-void camera_spin_around_cw_sitting( EKeystate s )
+bool camera_spin_around_cw_sitting( EKeystate s )
 {
-	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT ) return;
+	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_SLIDELEFT ) return true;
 	if (gAgent.rotateGrabbed() || gAgentCamera.sitCameraEnabled() || gAgent.getRunning())
 	{
 		//send keystrokes, but do not change camera
@@ -364,27 +382,30 @@ void camera_spin_around_cw_sitting( EKeystate s )
 		//change camera but do not send keystrokes
 		gAgentCamera.setOrbitRightKey( get_orbit_rate() );
 	}
+	return true;
 }
 
 
-void camera_spin_over( EKeystate s )
+bool camera_spin_over( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setOrbitUpKey( get_orbit_rate() );
+	return true;
 }
 
 
-void camera_spin_under( EKeystate s )
+bool camera_spin_under( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setOrbitDownKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_spin_over_sitting( EKeystate s )
+bool camera_spin_over_sitting( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	if (gAgent.upGrabbed() || gAgentCamera.sitCameraEnabled())
 	{
 		//send keystrokes, but do not change camera
@@ -395,12 +416,13 @@ void camera_spin_over_sitting( EKeystate s )
 		//change camera but do not send keystrokes
 		gAgentCamera.setOrbitUpKey( get_orbit_rate() );
 	}
+	return true;
 }
 
 
-void camera_spin_under_sitting( EKeystate s )
+bool camera_spin_under_sitting( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	if (gAgent.downGrabbed() || gAgentCamera.sitCameraEnabled())
 	{
 		//send keystrokes, but do not change camera
@@ -411,26 +433,29 @@ void camera_spin_under_sitting( EKeystate s )
 		//change camera but do not send keystrokes
 		gAgentCamera.setOrbitDownKey( get_orbit_rate() );
 	}
+	return true;
 }
 
-void camera_move_forward( EKeystate s )
+bool camera_move_forward( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setOrbitInKey( get_orbit_rate() );
+	return true;
 }
 
 
-void camera_move_backward( EKeystate s )
+bool camera_move_backward( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setOrbitOutKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_move_forward_sitting( EKeystate s )
+bool camera_move_forward_sitting( EKeystate s )
 {
-	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD ) return;
+	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_FORWARD ) return true;
 	if (gAgent.forwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun()))
 	{
 		agent_push_forward(s);
@@ -439,12 +464,13 @@ void camera_move_forward_sitting( EKeystate s )
 	{
 		gAgentCamera.setOrbitInKey( get_orbit_rate() );
 	}
+	return true;
 }
 
 
-void camera_move_backward_sitting( EKeystate s )
+bool camera_move_backward_sitting( EKeystate s )
 {
-	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD ) return;
+	if( KEYSTATE_UP == s && gAgent.mDoubleTapRunMode != LLAgent::DOUBLETAP_BACKWARD ) return true;
 
 	if (gAgent.backwardGrabbed() || gAgentCamera.sitCameraEnabled() || (gAgent.getRunning() && !gAgent.getAlwaysRun()))
 	{
@@ -454,139 +480,156 @@ void camera_move_backward_sitting( EKeystate s )
 	{
 		gAgentCamera.setOrbitOutKey( get_orbit_rate() );
 	}
+	return true;
 }
 
-void camera_pan_up( EKeystate s )
+bool camera_pan_up( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setPanUpKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_pan_down( EKeystate s )
+bool camera_pan_down( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setPanDownKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_pan_left( EKeystate s )
+bool camera_pan_left( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setPanLeftKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_pan_right( EKeystate s )
+bool camera_pan_right( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setPanRightKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_pan_in( EKeystate s )
+bool camera_pan_in( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setPanInKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_pan_out( EKeystate s )
+bool camera_pan_out( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setPanOutKey( get_orbit_rate() );
+	return true;
 }
 
-void camera_move_forward_fast( EKeystate s )
+bool camera_move_forward_fast( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setOrbitInKey(2.5f);
+	return true;
 }
 
-void camera_move_backward_fast( EKeystate s )
+bool camera_move_backward_fast( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gAgentCamera.unlockView();
 	gAgentCamera.setOrbitOutKey(2.5f);
+	return true;
 }
 
 
-void edit_avatar_spin_ccw( EKeystate s )
+bool edit_avatar_spin_ccw( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gMorphView->setCameraDrivenByKeys( TRUE );
 	gAgentCamera.setOrbitLeftKey( get_orbit_rate() );
 	//gMorphView->orbitLeft( get_orbit_rate() );
+	return true;
 }
 
 
-void edit_avatar_spin_cw( EKeystate s )
+bool edit_avatar_spin_cw( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gMorphView->setCameraDrivenByKeys( TRUE );
 	gAgentCamera.setOrbitRightKey( get_orbit_rate() );
 	//gMorphView->orbitRight( get_orbit_rate() );
+	return true;
 }
 
-void edit_avatar_spin_over( EKeystate s )
+bool edit_avatar_spin_over( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gMorphView->setCameraDrivenByKeys( TRUE );
 	gAgentCamera.setOrbitUpKey( get_orbit_rate() );
 	//gMorphView->orbitUp( get_orbit_rate() );
+	return true;
 }
 
 
-void edit_avatar_spin_under( EKeystate s )
+bool edit_avatar_spin_under( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gMorphView->setCameraDrivenByKeys( TRUE );
 	gAgentCamera.setOrbitDownKey( get_orbit_rate() );
 	//gMorphView->orbitDown( get_orbit_rate() );
+	return true;
 }
 
-void edit_avatar_move_forward( EKeystate s )
+bool edit_avatar_move_forward( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gMorphView->setCameraDrivenByKeys( TRUE );
 	gAgentCamera.setOrbitInKey( get_orbit_rate() );
 	//gMorphView->orbitIn();
+	return true;
 }
 
 
-void edit_avatar_move_backward( EKeystate s )
+bool edit_avatar_move_backward( EKeystate s )
 {
-	if( KEYSTATE_UP == s  ) return;
+	if( KEYSTATE_UP == s  ) return true;
 	gMorphView->setCameraDrivenByKeys( TRUE );
 	gAgentCamera.setOrbitOutKey( get_orbit_rate() );
 	//gMorphView->orbitOut();
+	return true;
 }
 
-void stop_moving( EKeystate s )
+bool stop_moving( EKeystate s )
 {
-	if( KEYSTATE_DOWN != s  ) return;
+	if( KEYSTATE_DOWN != s  ) return true;
 	// stop agent
 	gAgent.setControlFlags(AGENT_CONTROL_STOP);
 
 	// cancel autopilot
 	gAgent.stopAutoPilot();
+	return true;
 }
 
-void start_chat( EKeystate s )
+bool start_chat( EKeystate s )
 {
     if (LLAppViewer::instance()->quitRequested())
     {
-        return; // can't talk, gotta go, kthxbye!
+        return true; // can't talk, gotta go, kthxbye!
     }
-    if (KEYSTATE_DOWN != s) return;
+    if (KEYSTATE_DOWN != s) return true;
 
 	// start chat
 	LLFloaterIMNearbyChat::startChat(NULL);
+	return true;
 }
 
-void start_gesture( EKeystate s )
+bool start_gesture( EKeystate s )
 {
 	LLUICtrl* focus_ctrlp = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
 	if (KEYSTATE_UP == s &&
@@ -603,11 +646,12 @@ void start_gesture( EKeystate s )
  			LLFloaterIMNearbyChat::startChat(NULL);
  		}
 	}
+	return true;
 }
 
-void toggle_run(EKeystate s)
+bool toggle_run(EKeystate s)
 {
-    if (KEYSTATE_DOWN != s) return;
+    if (KEYSTATE_DOWN != s) return true;
     bool run = gAgent.getAlwaysRun();
     if (run)
     {
@@ -620,11 +664,12 @@ void toggle_run(EKeystate s)
         gAgent.setRunning();
     }
     gAgent.sendWalkRun(!run);
+	return true;
 }
 
-void toggle_sit(EKeystate s)
+bool toggle_sit(EKeystate s)
 {
-    if (KEYSTATE_DOWN != s) return;
+    if (KEYSTATE_DOWN != s) return true;
     if (gAgent.isSitting())
     {
         gAgent.standUp();
@@ -633,33 +678,75 @@ void toggle_sit(EKeystate s)
     {
         gAgent.sitDown();
     }
+	return true;
 }
 
-void toggle_pause_media(EKeystate s) // analogue of play/pause button in top bar
+bool toggle_pause_media(EKeystate s) // analogue of play/pause button in top bar
 {
-    if (KEYSTATE_DOWN != s) return;
+    if (KEYSTATE_DOWN != s) return true;
     bool pause = LLViewerMedia::isAnyMediaPlaying();
     LLViewerMedia::setAllMediaPaused(pause);
+    return true;
 }
 
-void toggle_enable_media(EKeystate s)
+bool toggle_enable_media(EKeystate s)
 {
-    if (KEYSTATE_DOWN != s) return;
+    if (KEYSTATE_DOWN != s) return true;
     bool pause = LLViewerMedia::isAnyMediaPlaying() || LLViewerMedia::isAnyMediaShowing();
     LLViewerMedia::setAllMediaEnabled(!pause);
+    return true;
 }
 
-void walk_to(EKeystate s)
+bool walk_to(EKeystate s)
 {
-    LL_WARNS() << "processing " << LLSD(s).asString() << LL_ENDL;
-    if (KEYSTATE_DOWN != s) return;
-    LLToolPie::getInstance()->walkToClickedLocation();
+    if (KEYSTATE_DOWN != s) return true;
+    return LLToolPie::getInstance()->walkToClickedLocation();
+}
+
+bool teleport_to(EKeystate s)
+{
+    if (KEYSTATE_DOWN != s) return true;
+    return LLToolPie::getInstance()->teleportToClickedLocation();
+}
+
+bool toggle_voice(EKeystate s)
+{
+    if (KEYSTATE_DOWN != s) return true;
+    if (!LLAgent::isActionAllowed("speak")) return false;
+    LLVoiceClient::getInstance()->toggleUserPTTState();
+    return true;
+}
+
+bool voice_follow_key(EKeystate s)
+{
+    if (KEYSTATE_DOWN == s)
+    {
+        if (!LLAgent::isActionAllowed("speak")) return false;
+        LLVoiceClient::getInstance()->setUserPTTState(true);
+        return true;
+    }
+    else if (KEYSTATE_UP == s && LLVoiceClient::getInstance()->getUserPTTState())
+    {
+        LLVoiceClient::getInstance()->setUserPTTState(false);
+        return true;
+    }
+    return false;
 }
 
-void teleport_to(EKeystate s)
+bool agen_control_lbutton_handle(EKeystate s)
 {
-    if (KEYSTATE_DOWN != s) return;
-    LLToolPie::getInstance()->teleportToClickedLocation();
+    switch (s)
+    {
+    case KEYSTATE_DOWN:
+        gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN);
+        break;
+    case KEYSTATE_UP:
+        gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP);
+        break;
+    default:
+        break;
+    }
+    return true;
 }
 
 #define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, ACTION);
@@ -709,6 +796,8 @@ REGISTER_KEYBOARD_ACTION("toggle_pause_media", toggle_pause_media);
 REGISTER_KEYBOARD_ACTION("toggle_enable_media", toggle_enable_media);
 REGISTER_KEYBOARD_ACTION("teleport_to", teleport_to);
 REGISTER_KEYBOARD_ACTION("walk_to", walk_to);
+REGISTER_KEYBOARD_ACTION("toggle_voice", toggle_voice);
+REGISTER_KEYBOARD_ACTION("voice_follow_key", voice_follow_key);
 #undef REGISTER_KEYBOARD_ACTION
 
 LLViewerKeyboard::LLViewerKeyboard()
@@ -844,7 +933,7 @@ BOOL LLViewerKeyboard::handleKeyUp(KEY translated_key, MASK translated_mask)
 BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const bool ignore, const std::string& function_name)
 {
 	S32 index;
-	typedef boost::function<void(EKeystate)> function_t;
+	typedef boost::function<bool(EKeystate)> function_t;
 	function_t function = NULL;
 	std::string name;
 
@@ -935,7 +1024,7 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c
 BOOL LLViewerKeyboard::bindMouse(const S32 mode, const EMouseClickType mouse, const MASK mask, const bool ignore, const std::string& function_name)
 {
     S32 index;
-    typedef boost::function<void(EKeystate)> function_t;
+    typedef boost::function<bool(EKeystate)> function_t;
     function_t function = NULL;
 
     function_t* result = LLKeyboardActionRegistry::getValue(function_name);
@@ -1105,102 +1194,6 @@ S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode,
 	return binding_count;
 }
 
-S32 LLViewerKeyboard::loadBindings(const std::string& filename)
-{
-	LLFILE *fp;
-	const S32 BUFFER_SIZE = 2048;
-	char buffer[BUFFER_SIZE];	/* Flawfinder: ignore */
-	// *NOTE: This buffer size is hard coded into scanf() below.
-	char mode_string[MAX_STRING] = "";	/* Flawfinder: ignore */
-	char key_string[MAX_STRING] = "";	/* Flawfinder: ignore */
-	char mask_string[MAX_STRING] = "";	/* Flawfinder: ignore */
-	char function_string[MAX_STRING] = "";	/* Flawfinder: ignore */
-	S32 mode = MODE_THIRD_PERSON;
-	KEY key = 0;
-	MASK mask = 0;
-	S32 tokens_read;
-	S32 binding_count = 0;
-	S32 line_count = 0;
-
-	if(filename.empty())
-	{
-		LL_ERRS() << " No filename specified" << LL_ENDL;
-		return 0;
-	}
-
-	fp = LLFile::fopen(filename, "r");
-
-	if (!fp)
-	{
-		return 0;
-	}
-
-
-	while (!feof(fp))
-	{
-		line_count++;
-		if (!fgets(buffer, BUFFER_SIZE, fp))
-			break;
-
-		// skip over comments, blank lines
-		if (buffer[0] == '#' || buffer[0] == '\n') continue;
-
-		// grab the binding strings
-		tokens_read = sscanf(	/* Flawfinder: ignore */
-			buffer,
-			"%254s %254s %254s %254s",
-			mode_string,
-			key_string,
-			mask_string,
-			function_string);
-
-		if (tokens_read == EOF)
-		{
-			LL_INFOS() << "Unexpected end-of-file at line " << line_count << " of key binding file " << filename << LL_ENDL;
-			fclose(fp);
-			return 0;
-		}
-		else if (tokens_read < 4)
-		{
-			LL_INFOS() << "Can't read line " << line_count << " of key binding file " << filename << LL_ENDL;
-			continue;
-		}
-
-		// convert mode
-		if (!modeFromString(mode_string, &mode))
-		{
-			LL_INFOS() << "Unknown mode on line " << line_count << " of key binding file " << filename << LL_ENDL;
-			LL_INFOS() << "Mode must be one of FIRST_PERSON, THIRD_PERSON, EDIT, EDIT_AVATAR" << LL_ENDL;
-			continue;
-		}
-
-		// convert key
-		if (!LLKeyboard::keyFromString(key_string, &key))
-		{
-			LL_INFOS() << "Can't interpret key on line " << line_count << " of key binding file " << filename << LL_ENDL;
-			continue;
-		}
-
-		// convert mask
-		if (!LLKeyboard::maskFromString(mask_string, &mask))
-		{
-			LL_INFOS() << "Can't interpret mask on line " << line_count << " of key binding file " << filename << LL_ENDL;
-			continue;
-		}
-
-		// bind key
-		if (bindKey(mode, key, mask, false, function_string))
-		{
-			binding_count++;
-		}
-	}
-
-	fclose(fp);
-
-	return binding_count;
-}
-
-
 EKeyboardMode LLViewerKeyboard::getMode() const
 {
 	if ( gAgentCamera.cameraMouselook() )
@@ -1236,27 +1229,26 @@ bool LLViewerKeyboard::scanKey(const LLKeyboardBinding* binding,
 		{
 			if (binding[i].mMask == mask)
 			{
+				bool res = false;
 				if (key_down && !repeat)
 				{
 					// ...key went down this frame, call function
-					binding[i].mFunction( KEYSTATE_DOWN );
+					res = binding[i].mFunction( KEYSTATE_DOWN );
 					return true;
 				}
 				else if (key_up)
 				{
 					// ...key went down this frame, call function
-					binding[i].mFunction( KEYSTATE_UP );
-					return true;
+					res = binding[i].mFunction( KEYSTATE_UP );
 				}
 				else if (key_level)
 				{
 					// ...key held down from previous frame
 					// Not windows, just call the function.
-					binding[i].mFunction( KEYSTATE_LEVEL );
-					return true;
+					res = binding[i].mFunction( KEYSTATE_LEVEL );
 				}//if
 				// Key+Mask combinations are supposed to be unique, so we won't find anything else
-				return false;
+				return res;
 			}//if
 		}//if
 	}//for
@@ -1264,7 +1256,7 @@ bool LLViewerKeyboard::scanKey(const LLKeyboardBinding* binding,
 }
 
 // Called from scanKeyboard.
-void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) const
+bool LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) const
 {
 	if (LLApp::isExiting())
 	{
@@ -1277,17 +1269,31 @@ void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_lev
 
 	if (mKeyHandledByUI[key])
 	{
-		return;
+		return false;
 	}
 
 	// don't process key down on repeated keys
 	BOOL repeat = gKeyboard->getKeyRepeated(key);
 
-    if (scanKey(mKeyBindings[mode], mKeyBindingCount[mode], key, mask, key_down, key_up, key_level, repeat))
+    bool res = scanKey(mKeyBindings[mode], mKeyBindingCount[mode], key, mask, key_down, key_up, key_level, repeat);
+    if (!res)
     {
         // Nothing found, try ignore list
-        scanKey(mKeyIgnoreMask[mode], mKeyIgnoreMaskCount[mode], key, MASK_NONE, key_down, key_up, key_level, repeat);
+        res = scanKey(mKeyIgnoreMask[mode], mKeyIgnoreMaskCount[mode], key, MASK_NONE, key_down, key_up, key_level, repeat);
     }
+
+    if (!res && agent_control_lbutton.canHandle(CLICK_NONE, key, mask))
+    {
+        if (key_down && !repeat)
+        {
+            res = agen_control_lbutton_handle(KEYSTATE_DOWN);
+        }
+        if (key_up)
+        {
+            res = agen_control_lbutton_handle(KEYSTATE_UP);
+        }
+    }
+    return res;
 }
 
 BOOL LLViewerKeyboard::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, EMouseClickType clicktype, BOOL down)
@@ -1368,23 +1374,30 @@ bool LLViewerKeyboard::scanMouse(const LLMouseBinding *binding, S32 binding_coun
     {
         if (binding[i].mMouse == mouse && binding[i].mMask == mask)
         {
+            bool res = false;
             switch (state)
             {
             case MOUSE_STATE_DOWN:
+                res = binding[i].mFunction(KEYSTATE_DOWN);
+                break;
             case MOUSE_STATE_CLICK:
-                binding[i].mFunction(KEYSTATE_DOWN);
+                // Button went down and up in scope of single frame
+                // might not work best with some functions,
+                // but some function need specific states specifically
+                res = binding[i].mFunction(KEYSTATE_DOWN);
+                res |= binding[i].mFunction(KEYSTATE_UP);
                 break;
             case MOUSE_STATE_LEVEL:
-                binding[i].mFunction(KEYSTATE_LEVEL);
+                res = binding[i].mFunction(KEYSTATE_LEVEL);
                 break;
             case MOUSE_STATE_UP:
-                binding[i].mFunction(KEYSTATE_UP);
+                res = binding[i].mFunction(KEYSTATE_UP);
                 break;
             default:
                 break;
             }
             // Key+Mask combinations are supposed to be unique, no need to continue
-            return true;
+            return res;
         }
     }
     return false;
@@ -1401,6 +1414,30 @@ bool LLViewerKeyboard::scanMouse(EMouseClickType click, EMouseState state) const
     {
         res = scanMouse(mMouseIgnoreMask[mode], mMouseIgnoreMaskCount[mode], click, MASK_NONE, state);
     }
+    // no user defined actions found or those actions can't handle the key/button, handle control if nessesary
+    if (!res && agent_control_lbutton.canHandle(click, KEY_NONE, mask))
+    {
+        switch (state)
+        {
+        case MOUSE_STATE_DOWN:
+            agen_control_lbutton_handle(KEYSTATE_DOWN);
+            res = true;
+            break;
+        case MOUSE_STATE_CLICK:
+            // might not work best with some functions,
+            // but some function need specific states too specifically
+            agen_control_lbutton_handle(KEYSTATE_DOWN);
+            agen_control_lbutton_handle(KEYSTATE_UP);
+            res = true;
+            break;
+        case MOUSE_STATE_UP:
+            agen_control_lbutton_handle(KEYSTATE_UP);
+            res = true;
+            break;
+        default:
+            break;
+        }
+    }
     return res;
 }
 
@@ -1413,7 +1450,7 @@ void LLViewerKeyboard::scanMouse()
             scanMouse((EMouseClickType)i, mMouseLevel[i]);
             if (mMouseLevel[i] == MOUSE_STATE_DOWN)
             {
-                // mouse doesn't support 'continued' state like keyboard does, so after handling, switch to LEVEL
+                // mouse doesn't support 'continued' state, so after handling, switch to LEVEL
                 mMouseLevel[i] = MOUSE_STATE_LEVEL;
             }
             else if (mMouseLevel[i] == MOUSE_STATE_UP || mMouseLevel[i] == MOUSE_STATE_CLICK)
diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h
index 10b16e5fa02086b49b9d40fb0690872e9bf0bf75..02fa21d4f2463ab75f4cba42dc078c261c02d70c 100644
--- a/indra/newview/llviewerkeyboard.h
+++ b/indra/newview/llviewerkeyboard.h
@@ -115,14 +115,16 @@ class LLViewerKeyboard
 	BOOL			handleKey(KEY key, MASK mask, BOOL repeated);
 	BOOL			handleKeyUp(KEY key, MASK mask);
 
-	S32				loadBindings(const std::string& filename);										// returns number bound, 0 on error
 	S32				loadBindingsXML(const std::string& filename);										// returns number bound, 0 on error
 	EKeyboardMode	getMode() 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 @@ class LLViewerKeyboard
     // 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 bd5370f07f9207b486a47d057e47242a3950e595..caf7a8a65a925b94f5f72967510682c434217a45 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -918,8 +918,6 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK m
 	x = ll_round((F32)x / mDisplayScale.mV[VX]);
 	y = ll_round((F32)y / mDisplayScale.mV[VY]);
 
-    LLVoiceClient::getInstance()->updateMouseState(clicktype, mask, down);
-
 	// only send mouse clicks to UI if UI is visible
 	if(gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
 	{	
@@ -1437,9 +1435,6 @@ void LLViewerWindow::handleFocusLost(LLWindow *window)
 
 BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key,  MASK mask, BOOL repeated)
 {
-	// Let the voice chat code check for its PTT key.  Note that this never affects event processing.
-	LLVoiceClient::getInstance()->keyDown(key, mask);
-
 	if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME)
 	{
 		gAgent.clearAFK();
@@ -1464,9 +1459,6 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key,  MASK mask, BOOL repeated)
 
 BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key,  MASK mask)
 {
-	// Let the voice chat code check for its PTT key.  Note that this never affects event processing.
-	LLVoiceClient::getInstance()->keyUp(key, mask);
-
 	// Let the inspect tool code check for ALT key to set LLToolSelectRect active instead LLToolCamera
 	LLToolCompInspect * tool_inspectp = LLToolCompInspect::getInstance();
 	if (LLToolMgr::getInstance()->getCurrentTool() == tool_inspectp)
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index fcca081647e45b0d0765bd571f6ab882de1b06ed..041f617ae5b30545f48960065c5095bce3f46d1f 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -199,8 +199,6 @@ const LLVoiceVersionInfo LLVoiceClient::getVersion()
 void LLVoiceClient::updateSettings()
 {
 	setUsePTT(gSavedSettings.getBOOL("PTTCurrentlyEnabled"));
-	std::string keyString = gSavedSettings.getString("PushToTalkButton");
-	setPTTKey(keyString);
 	setPTTIsToggle(gSavedSettings.getBOOL("PushToTalkToggle"));
 	mDisableMic = gSavedSettings.getBOOL("VoiceDisableMic");
 
@@ -636,32 +634,6 @@ bool LLVoiceClient::getPTTIsToggle()
 	return mPTTIsToggle;
 }
 
-void LLVoiceClient::setPTTKey(std::string &key)
-{
-	// Value is stored as text for readability
-	if(key == "MiddleMouse")
-	{
-		mPTTMouseButton = CLICK_MIDDLE;
-	}
-	else if(key == "MouseButton4")
-	{
-		mPTTMouseButton = CLICK_BUTTON4;
-	}
-	else if (key == "MouseButton5")
-	{
-		mPTTMouseButton = CLICK_BUTTON5;
-	}
-	else
-	{
-		mPTTMouseButton = 0;
-		if(!LLKeyboard::keyFromString(key, &mPTTKey))
-		{
-			// If the call failed, don't match any key.
-			key = KEY_NONE;
-		}
-	}
-}
-
 void LLVoiceClient::inputUserControlState(bool down)
 {
 	if(mPTTIsToggle)
@@ -682,48 +654,6 @@ void LLVoiceClient::toggleUserPTTState(void)
 	setUserPTTState(!getUserPTTState());
 }
 
-void LLVoiceClient::keyDown(KEY key, MASK mask)
-{	
-	if (gKeyboard->getKeyRepeated(key))
-	{
-		// ignore auto-repeat keys                                                                         
-		return;
-	}
-	
-    //
-	/*static LLCachedControl<LLSD> key_bind(gSavedSettings, "control_toggle_voice");
-    LLKeyBind bind(key_bind);
-	if (LLAgent::isActionAllowed("speak") && bind().canHandleKey(key, mask))
-	{
-		bool down = gKeyboard->getKeyDown(mPTTKey);
-		if (down)
-		{
-			inputUserControlState(down);
-		}
-	}*/
-	
-}
-void LLVoiceClient::keyUp(KEY key, MASK mask)
-{
-	/*static LLCachedControl<LLKeyBind> key_bind(gSavedSettings, "control_toggle_voice");
-	if (key_bind().canHandleKey(key, mask))
-	{
-		bool down = gKeyboard->getKeyDown(mPTTKey);
-		if (!down)
-		{
-			inputUserControlState(down);
-		}
-	}*/
-}
-void LLVoiceClient::updateMouseState(S32 click, MASK mask, bool down)
-{
-	/*static LLCachedControl<LLKeyBind> mouse_bind(gSavedSettings, "control_toggle_voice");
-	if (mouse_bind().canHandleMouse((EMouseClickType)click, mask))
-	{
-		inputUserControlState(down);
-	}*/
-}
-
 
 //-------------------------------------------
 // nearby speaker accessors
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index e3285b0c9bbe24b60d859e353594320dfda5dc62..52f4ff13b5d196e134f3e620f371c676feff4ddf 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -409,16 +409,10 @@ class LLVoiceClient: public LLSingleton<LLVoiceClient>
 	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 0c652845f0cba232101ec2ef3597c1f3c17fc209..ac4be34be25f17c41dee497327676aae661d69c9 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"