From 2d855a9fd7ea0ef32f8d9de81b2532b3771142e4 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 16 Jul 2021 22:45:41 +0300
Subject: SL-15594 Reimplement previous voice keybind behavior

Also fixed dupplicate checks
---
 indra/newview/llviewerinput.cpp  | 159 +++++++++++++++++++++++++++++++--------
 indra/newview/llviewerinput.h    |  11 +++
 indra/newview/llviewerwindow.cpp |  12 ++-
 3 files changed, 150 insertions(+), 32 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index f269be035e..77b0c8e37b 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -60,8 +60,21 @@ const F32 ORBIT_NUDGE_RATE = 0.05f;  // fraction of normal speed
 
 const LLKeyData agent_control_lbutton(CLICK_LEFT, KEY_NONE, MASK_NONE, true);
 
+struct LLKeybindFunctionData
+{
+    LLKeybindFunctionData(boost::function<bool(EKeystate keystate)> function, bool global)
+        :
+        mFunction(function),
+        mIsGlobal(global)
+    {
+    }
+    boost::function<bool(EKeystate keystate)> mFunction;
+    // todo: might be good idea to make this into enum, like: global/inworld/menu
+    bool mIsGlobal;
+};
+
 struct LLKeyboardActionRegistry 
-:	public LLRegistrySingleton<std::string, boost::function<bool (EKeystate keystate)>, LLKeyboardActionRegistry>
+:	public LLRegistrySingleton<const std::string, LLKeybindFunctionData, LLKeyboardActionRegistry>
 {
 	LLSINGLETON_EMPTY_CTOR(LLKeyboardActionRegistry);
 };
@@ -852,7 +865,10 @@ bool agen_control_lbutton_handle(EKeystate s)
     return true;
 }
 
-#define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, ACTION);
+// In-world keybindings, like walking or camera
+#define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, LLKeybindFunctionData(ACTION, false));
+// Global keybindings that should work even with floaters focused, like voice
+#define REGISTER_KEYBOARD_GLOBAL_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, LLKeybindFunctionData(ACTION, true));
 REGISTER_KEYBOARD_ACTION("jump", agent_jump);
 REGISTER_KEYBOARD_ACTION("push_down", agent_push_down);
 REGISTER_KEYBOARD_ACTION("push_forward", agent_push_forward);
@@ -903,8 +919,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);
+REGISTER_KEYBOARD_GLOBAL_ACTION("toggle_voice", toggle_voice);
+REGISTER_KEYBOARD_GLOBAL_ACTION("voice_follow_key", voice_follow_key);
 #undef REGISTER_KEYBOARD_ACTION
 
 LLViewerInput::LLViewerInput()
@@ -1034,6 +1050,29 @@ BOOL LLViewerInput::handleKeyUp(KEY translated_key, MASK translated_mask)
 	return gViewerWindow->handleKeyUp(translated_key, translated_mask);
 }
 
+bool LLViewerInput::handleGlobalBindsKeyDown(KEY key, MASK mask)
+{
+    S32 mode = getMode();
+    return scanKey(mGlobalKeyBindings[mode], mGlobalKeyBindings[mode].size(), key, mask, TRUE, FALSE, FALSE, FALSE);
+}
+
+bool LLViewerInput::handleGlobalBindsKeyUp(KEY key, MASK mask)
+{
+    S32 mode = getMode();
+    return scanKey(mGlobalKeyBindings[mode], mGlobalKeyBindings[mode].size(), key, mask, FALSE, TRUE, FALSE, FALSE);
+}
+
+bool LLViewerInput::handleGlobalBindsMouse(EMouseClickType clicktype, MASK mask, bool down)
+{
+    bool res = false;
+    if (down)
+    {
+        S32 mode = getMode();
+        res = scanMouse(mGlobalMouseBindings[mode], mGlobalMouseBindings[mode].size(), clicktype, mask, MOUSE_STATE_DOWN);
+    }
+    return res;
+}
+
 BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name)
 {
 	S32 index;
@@ -1061,39 +1100,64 @@ BOOL LLViewerInput::bindKey(const S32 mode, const KEY key, const MASK mask, cons
 	}
 
 	// Not remapped, look for a function
-	
-	function_t* result = LLKeyboardActionRegistry::getValue(function_name);
+
+    LLKeybindFunctionData* result = LLKeyboardActionRegistry::getValue(function_name);
 	if (result)
 	{
-		function = *result;
+		function = result->mFunction;
 	}
 
 	if (!function)
 	{
-		LL_WARNS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
+		LL_WARNS_ONCE() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL;
 		return FALSE;
 	}
 
-	// check for duplicate first and overwrite
-    S32 size = mKeyBindings[mode].size();
-    for (index = 0; index < size; index++)
+    if (mode >= MODE_COUNT)
     {
-        if (key == mKeyBindings[mode][index].mKey && mask == mKeyBindings[mode][index].mMask)
-            break;
+        LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
+        return FALSE;
     }
 
-	if (mode >= MODE_COUNT)
-	{
-		LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
-		return FALSE;
-	}
+	// check for duplicate first and overwrite
+    if (result->mIsGlobal)
+    {
+        S32 size = mGlobalKeyBindings[mode].size();
+        for (index = 0; index < size; index++)
+        {
+            if (key == mGlobalKeyBindings[mode][index].mKey && mask == mGlobalKeyBindings[mode][index].mMask)
+            {
+                mGlobalKeyBindings[mode][index].mFunction = function;
+                return TRUE;
+            }
+        }
+    }
+    else
+    {
+        S32 size = mKeyBindings[mode].size();
+        for (index = 0; index < size; index++)
+        {
+            if (key == mKeyBindings[mode][index].mKey && mask == mKeyBindings[mode][index].mMask)
+            {
+                mKeyBindings[mode][index].mFunction = function;
+                return TRUE;
+            }
+        }
+    }
 
     LLKeyboardBinding bind;
     bind.mKey = key;
     bind.mMask = mask;
     bind.mFunction = function;
 
-    mKeyBindings[mode].push_back(bind);
+    if (result->mIsGlobal)
+    {
+        mGlobalKeyBindings[mode].push_back(bind);
+    }
+    else
+    {
+        mKeyBindings[mode].push_back(bind);
+    }
 
 	return TRUE;
 }
@@ -1104,38 +1168,63 @@ BOOL LLViewerInput::bindMouse(const S32 mode, const EMouseClickType mouse, const
     typedef boost::function<bool(EKeystate)> function_t;
     function_t function = NULL;
 
-    function_t* result = LLKeyboardActionRegistry::getValue(function_name);
+    LLKeybindFunctionData* result = LLKeyboardActionRegistry::getValue(function_name);
     if (result)
     {
-        function = *result;
+        function = result->mFunction;
     }
 
     if (!function)
     {
-        LL_WARNS() << "Can't bind mouse key to function " << function_name << ", no function with this name found" << LL_ENDL;
+        LL_WARNS_ONCE() << "Can't bind mouse key to function " << function_name << ", no function with this name found" << LL_ENDL;
         return FALSE;
     }
 
-    // check for duplicate first and overwrite
-    S32 size = mMouseBindings[mode].size();
-    for (index = 0; index < size; index++)
-    {
-        if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask)
-            break;
-    }
-
     if (mode >= MODE_COUNT)
     {
         LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL;
         return FALSE;
     }
 
+    // check for duplicate first and overwrite
+    if (result->mIsGlobal)
+    {
+        S32 size = mGlobalMouseBindings[mode].size();
+        for (index = 0; index < size; index++)
+        {
+            if (mouse == mGlobalMouseBindings[mode][index].mMouse && mask == mGlobalMouseBindings[mode][index].mMask)
+            {
+                mGlobalMouseBindings[mode][index].mFunction = function;
+                return true;
+            }
+        }
+    }
+    else
+    {
+        S32 size = mMouseBindings[mode].size();
+        for (index = 0; index < size; index++)
+        {
+            if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask)
+            {
+                mMouseBindings[mode][index].mFunction = function;
+                return true;
+            }
+        }
+    }
+
     LLMouseBinding bind;
     bind.mMouse = mouse;
     bind.mMask = mask;
     bind.mFunction = function;
 
-    mMouseBindings[mode].push_back(bind);
+    if (result->mIsGlobal)
+    {
+        mGlobalMouseBindings[mode].push_back(bind);
+    }
+    else
+    {
+        mMouseBindings[mode].push_back(bind);
+    }
 
     return TRUE;
 }
@@ -1162,6 +1251,8 @@ void LLViewerInput::resetBindings()
 {
     for (S32 i = 0; i < MODE_COUNT; i++)
     {
+        mGlobalKeyBindings[i].clear();
+        mGlobalMouseBindings[i].clear();
         mKeyBindings[i].clear();
         mMouseBindings[i].clear();
     }
@@ -1536,5 +1627,11 @@ bool LLViewerInput::isMouseBindUsed(const EMouseClickType mouse, const MASK mask
         if (mouse == mMouseBindings[mode][index].mMouse && mask == mMouseBindings[mode][index].mMask)
             return true;
     }
+    size = mGlobalMouseBindings[mode].size();
+    for (S32 index = 0; index < size; index++)
+    {
+        if (mouse == mGlobalMouseBindings[mode][index].mMouse && mask == mGlobalMouseBindings[mode][index].mMask)
+            return true;
+    }
     return false;
 }
diff --git a/indra/newview/llviewerinput.h b/indra/newview/llviewerinput.h
index 281a209896..8401f8cd95 100644
--- a/indra/newview/llviewerinput.h
+++ b/indra/newview/llviewerinput.h
@@ -109,6 +109,13 @@ public:
 	BOOL			handleKey(KEY key, MASK mask, BOOL repeated);
 	BOOL			handleKeyUp(KEY key, MASK mask);
 
+    // Handle 'global' keybindings that do not consume event,
+    // yet need to be processed early
+    // Example: we want voice to toggle even if some floater is focused
+    bool			handleGlobalBindsKeyDown(KEY key, MASK mask);
+    bool			handleGlobalBindsKeyUp(KEY key, MASK mask);
+    bool			handleGlobalBindsMouse(EMouseClickType clicktype, MASK mask, bool down);
+
 	S32				loadBindingsXML(const std::string& filename);										// returns number bound, 0 on error
 	EKeyboardMode	getMode() const;
 
@@ -164,6 +171,10 @@ private:
     std::vector<LLKeyboardBinding>	mKeyBindings[MODE_COUNT];
     std::vector<LLMouseBinding>		mMouseBindings[MODE_COUNT];
 
+    // keybindings that do not consume event and are handled earlier, before floaters
+    std::vector<LLKeyboardBinding>	mGlobalKeyBindings[MODE_COUNT];
+    std::vector<LLMouseBinding>		mGlobalMouseBindings[MODE_COUNT];
+
 	typedef std::map<U32, U32> key_remap_t;
 	key_remap_t		mRemapKeys[MODE_COUNT];
 	std::set<KEY>	mKeysSkippedByUI;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 21985d5a8a..b0462f8ba7 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -54,7 +54,6 @@
 #include "llslurl.h"
 #include "llrender.h"
 
-#include "llvoiceclient.h"	// for push-to-talk button handling
 #include "stringize.h"
 
 //
@@ -1057,6 +1056,9 @@ 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]);
 
+    // Handle non-consuming global keybindings, like voice 
+    gViewerInput.handleGlobalBindsMouse(clicktype, mask, down);
+
 	// only send mouse clicks to UI if UI is visible
 	if(gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
 	{	
@@ -1577,6 +1579,10 @@ void LLViewerWindow::handleFocusLost(LLWindow *window)
 
 BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key,  MASK mask, BOOL repeated)
 {
+    // Handle non-consuming global keybindings, like voice 
+    // Never affects event processing.
+    gViewerInput.handleGlobalBindsKeyDown(key, mask);
+
 	if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME)
 	{
 		gAgent.clearAFK();
@@ -1601,6 +1607,10 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key,  MASK mask, BOOL repeated)
 
 BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key,  MASK mask)
 {
+    // Handle non-consuming global keybindings, like voice 
+    // Never affects event processing.
+    gViewerInput.handleGlobalBindsKeyUp(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)
-- 
cgit v1.2.3