From ca49ad736a06aa796610f068f6419c39b8535251 Mon Sep 17 00:00:00 2001
From: callum_linden <none@none>
Date: Fri, 10 Jul 2015 01:01:07 +0100
Subject: Initial support for keyboard (in progress) but includes many viewer
 changes to plumb in Key Up events

---
 indra/llui/llfocusmgr.cpp                    |   6 +
 indra/llui/llfocusmgr.h                      |   1 +
 indra/llui/llview.cpp                        |  46 +++++++
 indra/llui/llview.h                          |   3 +
 indra/media_plugins/cef/media_plugin_cef.cpp | 189 +++++++++++++++++++++++----
 indra/newview/llmediactrl.cpp                |  27 +++-
 indra/newview/llmediactrl.h                  |   3 +-
 indra/newview/llviewerkeyboard.cpp           |   5 +-
 indra/newview/llviewerkeyboard.h             |   1 +
 indra/newview/llviewermedia.cpp              |  41 ++++--
 indra/newview/llviewermedia.h                |   1 +
 indra/newview/llviewermediafocus.cpp         |   7 +
 indra/newview/llviewermediafocus.h           |   1 +
 indra/newview/llviewerwindow.cpp             |  38 +++++-
 indra/newview/llviewerwindow.h               |   3 +-
 15 files changed, 324 insertions(+), 48 deletions(-)

(limited to 'indra')

diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp
index 547f0bd398..fb811452be 100755
--- a/indra/llui/llfocusmgr.cpp
+++ b/indra/llui/llfocusmgr.cpp
@@ -46,6 +46,12 @@ BOOL LLFocusableElement::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 	return FALSE;
 }
 
+// virtual
+BOOL LLFocusableElement::handleKeyUp(KEY key, MASK mask, BOOL called_from_parent)
+{
+	return FALSE;
+}
+
 // virtual
 BOOL LLFocusableElement::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
 {
diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h
index afd2a8ce06..950ac55325 100755
--- a/indra/llui/llfocusmgr.h
+++ b/indra/llui/llfocusmgr.h
@@ -57,6 +57,7 @@ public:
 
 	// These were brought up the hierarchy from LLView so that we don't have to use dynamic_cast when dealing with keyboard focus.
 	virtual BOOL	handleKey(KEY key, MASK mask, BOOL called_from_parent);
+	virtual BOOL	handleKeyUp(KEY key, MASK mask, BOOL called_from_parent);
 	virtual BOOL	handleUnicodeChar(llwchar uni_char, BOOL called_from_parent);
 
 	virtual void	onTopLost();	// called when registered as top ctrl and user clicks elsewhere
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index a8beb9cfc9..8f7cac1f61 100755
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -866,6 +866,7 @@ BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
 
 	return handled;
 }
+
 BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 {
 	BOOL handled = FALSE;
@@ -898,6 +899,38 @@ BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 	return handled;
 }
 
+BOOL LLView::handleKeyUp(KEY key, MASK mask, BOOL called_from_parent)
+{
+	BOOL handled = FALSE;
+
+	if (getVisible() && getEnabled())
+	{
+		if (called_from_parent)
+		{
+			// Downward traversal
+			handled = childrenHandleKeyUp(key, mask) != NULL;
+		}
+
+		if (!handled)
+		{
+			// For event logging we don't care which widget handles it
+			// So we capture the key at the end of this function once we know if it was handled
+			handled = handleKeyUpHere(key, mask);
+			if (handled)
+			{
+				LL_DEBUGS() << "Key handled by " << getName() << LL_ENDL;
+			}
+		}
+	}
+
+	if (!handled && !called_from_parent && mParentView)
+	{
+		// Upward traversal
+		handled = mParentView->handleKeyUp(key, mask, FALSE);
+	}
+	return handled;
+}
+
 // Called from handleKey()
 // Handles key in this object.  Checking parents and children happens in handleKey()
 BOOL LLView::handleKeyHere(KEY key, MASK mask)
@@ -905,6 +938,13 @@ BOOL LLView::handleKeyHere(KEY key, MASK mask)
 	return FALSE;
 }
 
+// Called from handleKey()
+// Handles key in this object.  Checking parents and children happens in handleKey()
+BOOL LLView::handleKeyUpHere(KEY key, MASK mask)
+{
+	return FALSE;
+}
+
 BOOL LLView::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
 {
 	BOOL handled = FALSE;
@@ -1020,6 +1060,12 @@ LLView* LLView::childrenHandleKey(KEY key, MASK mask)
 	return childrenHandleCharEvent("Key", &LLView::handleKey, key, mask);
 }
 
+// Called during downward traversal
+LLView* LLView::childrenHandleKeyUp(KEY key, MASK mask)
+{
+	return childrenHandleCharEvent("Key Up", &LLView::handleKeyUp, key, mask);
+}
+
 // Called during downward traversal
 LLView* LLView::childrenHandleUnicodeChar(llwchar uni_char)
 {
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 7861c8f729..8494bb338a 100755
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -378,6 +378,7 @@ public:
 
 	// inherited from LLFocusableElement
 	/* virtual */ BOOL	handleKey(KEY key, MASK mask, BOOL called_from_parent);
+	/* virtual */ BOOL	handleKeyUp(KEY key, MASK mask, BOOL called_from_parent);
 	/* virtual */ BOOL	handleUnicodeChar(llwchar uni_char, BOOL called_from_parent);
 
 	virtual BOOL	handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
@@ -509,6 +510,7 @@ public:
 	
 	//virtual BOOL	addChildFromParam(const LLInitParam::BaseBlock& params) { return TRUE; }
 	virtual BOOL	handleKeyHere(KEY key, MASK mask);
+	virtual BOOL	handleKeyUpHere(KEY key, MASK mask);
 	virtual BOOL	handleUnicodeCharHere(llwchar uni_char);
 
 	virtual void	handleReshape(const LLRect& rect, bool by_user);
@@ -538,6 +540,7 @@ protected:
 	void			logMouseEvent();
 
 	LLView*	childrenHandleKey(KEY key, MASK mask);
+	LLView*	childrenHandleKeyUp(KEY key, MASK mask);
 	LLView* childrenHandleUnicodeChar(llwchar uni_char);
 	LLView*	childrenHandleDragAndDrop(S32 x, S32 y, MASK mask,
 											  BOOL drop,
diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp
index ccb8a93f87..f4ffd6d634 100644
--- a/indra/media_plugins/cef/media_plugin_cef.cpp
+++ b/indra/media_plugins/cef/media_plugin_cef.cpp
@@ -27,6 +27,7 @@
 */
 
 #include "linden_common.h"
+#include "indra_constants.h" // for indra keyboard codes
 
 #include "llgl.h"
 #include "llplugininstance.h"
@@ -64,6 +65,12 @@ private:
 
 	void postDebugMessage(const std::string& msg);
 
+
+	EKeyboardModifier decodeModifiers(std::string &modifiers);
+	void deserializeKeyboardData(LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers);
+	void keyEvent(EKeyEvent key_event, int key, EKeyboardModifier modifiers, LLSD native_key_data);
+	void unicodeInput(const std::string &utf8str, EKeyboardModifier modifiers, LLSD native_key_data);
+
 	bool mEnableMediaPluginDebugging;
 	LLCEFLib* mLLCEFLib;
 };
@@ -273,15 +280,15 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
 				mLLCEFLib->setOnLoadEndCallback(boost::bind(&MediaPluginCEF::onLoadEndCallback, this, _1));
 				mLLCEFLib->setOnNavigateURLCallback(boost::bind(&MediaPluginCEF::onNavigateURLCallback, this, _1));
 
-	            LLCEFLibSettings settings;
-	            settings.inital_width = 1024;
-	            settings.inital_height = 1024;
-	            settings.javascript_enabled = true;
-	            settings.cookies_enabled = true;
+				LLCEFLibSettings settings;
+				settings.inital_width = 1024;
+				settings.inital_height = 1024;
+				settings.javascript_enabled = true;
+				settings.cookies_enabled = true;
 				bool result = mLLCEFLib->init(settings);
 				if (!result)
 				{
-// TODO - return something to indicate failure
+					// TODO - return something to indicate failure
 					//MessageBoxA(0, "FAIL INIT", 0, 0);
 				}
 
@@ -339,7 +346,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
 			else if (message_name == "mouse_event")
 			{
 				std::string event = message_in.getValue("event");
-				
+
 				S32 x = message_in.getValueS32("x");
 				S32 y = message_in.getValueS32("y");
 
@@ -354,6 +361,8 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
 				if (event == "down")
 				{
 					mLLCEFLib->mouseButton(btn, ME_MOUSE_DOWN, x, y);
+					mLLCEFLib->setFocus(true);
+
 					std::stringstream str;
 					str << "Mouse down at = " << x << ", " << y;
 					postDebugMessage(str.str());
@@ -361,6 +370,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
 				else if (event == "up")
 				{
 					mLLCEFLib->mouseButton(btn, ME_MOUSE_UP, x, y);
+
 					std::stringstream str;
 					str << "Mouse up at = " << x << ", " << y;
 					postDebugMessage(str.str());
@@ -384,42 +394,31 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
 			}
 			else if (message_name == "text_event")
 			{
-				std::string event = message_in.getValue("event");
-				S32 key = message_in.getValue("text")[0];
+				std::string text = message_in.getValue("text");
 				std::string modifiers = message_in.getValue("modifiers");
 				LLSD native_key_data = message_in.getValueLLSD("native_key_data");
 
-				//int native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
-
-				//if (event == "down")
-				{
-					mLLCEFLib->keyPress(key, true);
-				}
-				//else
-				//if (event == "up")
-				{
-					mLLCEFLib->keyPress(key, false);
-				}
+				unicodeInput(text, decodeModifiers(modifiers), native_key_data);
 			}
 			else if (message_name == "key_event")
 			{
 				std::string event = message_in.getValue("event");
-				//S32 key = message_in.getValueS32("key");
+				S32 key = message_in.getValueS32("key");
 				std::string modifiers = message_in.getValue("modifiers");
 				LLSD native_key_data = message_in.getValueLLSD("native_key_data");
 
-				int native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
-				native_scan_code = 8;
-
+				// Treat unknown events as key-up for safety.
+				EKeyEvent key_event = KE_KEY_UP;
 				if (event == "down")
 				{
-					mLLCEFLib->keyPress(native_scan_code, true);
+					key_event = KE_KEY_DOWN;
 				}
-				else
-				if (event == "up")
+				else if (event == "repeat")
 				{
-					mLLCEFLib->keyPress(native_scan_code, false);
+					key_event = KE_KEY_REPEAT;
 				}
+
+				keyEvent(key_event, key, decodeModifiers(modifiers), native_key_data);
 			}
 			else if (message_name == "enable_media_plugin_debugging")
 			{
@@ -458,6 +457,140 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
 	}
 }
 
+EKeyboardModifier MediaPluginCEF::decodeModifiers(std::string &modifiers)
+{
+	int result = 0;
+
+	if (modifiers.find("shift") != std::string::npos)
+		result |= KM_MODIFIER_SHIFT;
+
+	if (modifiers.find("alt") != std::string::npos)
+		result |= KM_MODIFIER_ALT;
+
+	if (modifiers.find("control") != std::string::npos)
+		result |= KM_MODIFIER_CONTROL;
+
+	if (modifiers.find("meta") != std::string::npos)
+		result |= KM_MODIFIER_META;
+
+	return (EKeyboardModifier)result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::deserializeKeyboardData(LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers)
+{
+	native_scan_code = 0;
+	native_virtual_key = 0;
+	native_modifiers = 0;
+
+	if (native_key_data.isMap())
+	{
+#if LL_DARWIN
+		native_scan_code = (uint32_t)(native_key_data["char_code"].asInteger());
+		native_virtual_key = (uint32_t)(native_key_data["key_code"].asInteger());
+		native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger());
+#elif LL_WINDOWS
+		native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
+		native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
+		// TODO: I don't think we need to do anything with native modifiers here -- please verify
+#endif 
+	};
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::keyEvent(EKeyEvent key_event, int key, EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
+{
+	// The incoming values for 'key' will be the ones from indra_constants.h
+	std::string utf8_text;
+
+	if (key < 128)
+	{
+		// Low-ascii characters need to get passed through.
+		utf8_text = (char)key;
+	}
+
+	// Any special-case handling we want to do for particular keys...
+	switch ((KEY)key)
+	{
+		// ASCII codes for some standard keys
+		case KEY_BACKSPACE:		utf8_text = (char)8;		break;
+		case KEY_TAB:			utf8_text = (char)9;		break;
+		case KEY_RETURN:		utf8_text = (char)13;		break;
+		case KEY_PAD_RETURN:	utf8_text = (char)13;		break;
+		case KEY_ESCAPE:		utf8_text = (char)27;		break;
+
+	default:
+		break;
+	}
+
+	uint32_t native_scan_code = 0;
+	uint32_t native_virtual_key = 0;
+	uint32_t native_modifiers = 0;
+	deserializeKeyboardData(native_key_data, native_scan_code, native_virtual_key, native_modifiers);
+
+	//std::stringstream str;
+	//str << "@@@@@ KEYBOARD EVENT native_modifiers = " << native_modifiers;
+	//postDebugMessage(str.str());
+
+	mLLCEFLib->keyboardEvent(key_event, (uint32_t)key, utf8_text.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
+
+
+	std::stringstream str;
+	str << "@@@@@@@@@@@@@@@@ MediaPluginCEF::keyEvent";
+	postDebugMessage(str.str());
+
+	//uint32_t msg = native_key_data["msg"].asInteger();
+	//uint32_t wparam = native_key_data["w_param"].asInteger();
+	//uint64_t lparam = native_key_data["l_param"].asInteger();
+
+	//std::stringstream str;
+	//str << "@@@@@@@@@@@@@@@@ keyEvent Native message" << msg << ", " << wparam << ", " << lparam;
+	//postDebugMessage(str.str());
+
+	//mLLCEFLib->nativeKeyboardEvent(msg, wparam, lparam);
+
+
+	//checkEditState();
+};
+
+void MediaPluginCEF::unicodeInput(const std::string &utf8str, EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
+{
+	uint32_t key = KEY_NONE;
+
+	if (utf8str.size() == 1)
+	{
+		// The only way a utf8 string can be one byte long is if it's actually a single 7-bit ascii character.
+		// In this case, use it as the key value.
+		key = utf8str[0];
+	}
+
+	uint32_t native_scan_code = 0;
+	uint32_t native_virtual_key = 0;
+	uint32_t native_modifiers = 0;
+	deserializeKeyboardData(native_key_data, native_scan_code, native_virtual_key, native_modifiers);
+
+	std::stringstream str;
+	str << "@@@@@@@@@@@@@@@@ MediaPluginCEF::unicodeInput";
+	postDebugMessage(str.str());
+
+	//uint32_t msg = native_key_data["msg"].asInteger();
+	//uint32_t wparam = native_key_data["w_param"].asInteger();
+	//uint64_t lparam = native_key_data["l_param"].asInteger();
+
+	//std::stringstream str;
+	//str << "@@@@@@@@@@@@@@@@ unicodeInput Native message" << msg << ", " << wparam << ", " << lparam;
+	//postDebugMessage(str.str());
+
+	//mLLCEFLib->nativeKeyboardEvent(msg, wparam, lparam);
+
+	mLLCEFLib->keyboardEvent(KE_KEY_DOWN, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
+	mLLCEFLib->keyboardEvent(KE_KEY_UP, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
+
+	//	checkEditState();
+};
+
 ////////////////////////////////////////////////////////////////////////////////
 //
 bool MediaPluginCEF::init()
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index b96bdd73ff..d1bb799015 100755
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -410,18 +410,35 @@ void LLMediaCtrl::onOpenWebInspector()
 
 ////////////////////////////////////////////////////////////////////////////////
 //
-BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask )
+BOOL LLMediaCtrl::handleKeyHere(KEY key, MASK mask)
 {
 	BOOL result = FALSE;
-	
+
 	if (mMediaSource)
 	{
 		result = mMediaSource->handleKeyHere(key, mask);
 	}
-	
-	if ( ! result )
+
+	if (!result)
 		result = LLPanel::handleKeyHere(key, mask);
-		
+
+	return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+BOOL LLMediaCtrl::handleKeyUpHere(KEY key, MASK mask)
+{
+	BOOL result = FALSE;
+
+	if (mMediaSource)
+	{
+		result = mMediaSource->handleKeyUpHere(key, mask);
+	}
+
+	if (!result)
+		result = LLPanel::handleKeyUpHere(key, mask);
+
 	return result;
 }
 
diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h
index 785c57b78a..469ff38ee6 100755
--- a/indra/newview/llmediactrl.h
+++ b/indra/newview/llmediactrl.h
@@ -150,7 +150,8 @@ public:
 		void setTrustedContent(bool trusted);
 
 		// over-rides
-		virtual BOOL handleKeyHere( KEY key, MASK mask);
+		virtual BOOL handleKeyHere(KEY key, MASK mask);
+		virtual BOOL handleKeyUpHere(KEY key, MASK mask);
 		virtual void onVisibilityChange ( BOOL new_visibility );
 		virtual BOOL handleUnicodeCharHere(llwchar uni_char);
 		virtual void reshape( S32 width, S32 height, BOOL called_from_parent = TRUE);
diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp
index ada829eb4b..1ab672aafc 100755
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -729,7 +729,10 @@ BOOL LLViewerKeyboard::handleKey(KEY translated_key,  MASK translated_mask, BOOL
 	return mKeyHandledByUI[translated_key];
 }
 
-
+BOOL LLViewerKeyboard::handleKeyUp(KEY translated_key, MASK translated_mask)
+{
+	return gViewerWindow->handleKeyUp(translated_key, translated_mask);
+}
 
 BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name)
 {
diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h
index ca73212ed1..110dc89d28 100755
--- a/indra/newview/llviewerkeyboard.h
+++ b/indra/newview/llviewerkeyboard.h
@@ -89,6 +89,7 @@ public:
 	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
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index aa4943b8e8..60a5f99e19 100755
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -2698,27 +2698,48 @@ void LLViewerMediaImpl::navigateStop()
 bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask)
 {
 	bool result = false;
-	
+
 	if (mMediaSource)
 	{
 		// FIXME: THIS IS SO WRONG.
 		// Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it...
-		if( MASK_CONTROL & mask && key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END)
+		if (MASK_CONTROL & mask && key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END)
 		{
 			result = true;
 		}
-		
-		if(!result)
+
+		if (!result)
 		{
-			
+
 			LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData();
-			
-			result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask, native_key_data);
-			// Since the viewer internal event dispatching doesn't give us key-up events, simulate one here.
-			(void)mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask, native_key_data);
+			result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN, key, mask, native_key_data);
 		}
 	}
-	
+
+	return result;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+bool LLViewerMediaImpl::handleKeyUpHere(KEY key, MASK mask)
+{
+	bool result = false;
+
+	if (mMediaSource)
+	{
+		// FIXME: THIS IS SO WRONG.
+		// Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it...
+		if (MASK_CONTROL & mask && key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END)
+		{
+			result = true;
+		}
+
+		if (!result)
+		{
+			LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData();
+			result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP, key, mask, native_key_data);
+		}
+	}
+
 	return result;
 }
 
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index 6803adfaa2..f2da30e10b 100755
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -238,6 +238,7 @@ public:
 	void navigateInternal();
 	void navigateStop();
 	bool handleKeyHere(KEY key, MASK mask);
+	bool handleKeyUpHere(KEY key, MASK mask);
 	bool handleUnicodeCharHere(llwchar uni_char);
 	bool canNavigateForward();
 	bool canNavigateBack();
diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp
index aa019dfdd8..1265ca0a70 100755
--- a/indra/newview/llviewermediafocus.cpp
+++ b/indra/newview/llviewermediafocus.cpp
@@ -352,6 +352,13 @@ BOOL LLViewerMediaFocus::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 	return true;
 }
 
+BOOL LLViewerMediaFocus::handleKeyUp(KEY key, MASK mask, BOOL called_from_parent)
+{
+	return true;
+}
+
+
+
 BOOL LLViewerMediaFocus::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
 {
 	LLViewerMediaImpl* media_impl = getFocusedMediaImpl();
diff --git a/indra/newview/llviewermediafocus.h b/indra/newview/llviewermediafocus.h
index f03dd8751e..42c841df15 100755
--- a/indra/newview/llviewermediafocus.h
+++ b/indra/newview/llviewermediafocus.h
@@ -56,6 +56,7 @@ public:
 	
 	/*virtual*/ bool	getFocus();
 	/*virtual*/ BOOL	handleKey(KEY key, MASK mask, BOOL called_from_parent);
+	/*virtual*/ BOOL	handleKeyUp(KEY key, MASK mask, BOOL called_from_parent);
 	/*virtual*/ BOOL	handleUnicodeChar(llwchar uni_char, BOOL called_from_parent);
 	BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
 
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index e317989f04..ed4acfddc4 100755
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1399,10 +1399,9 @@ BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key,  MASK mask)
 		tool_inspectp->keyUp(key, mask);
 	}
 
-	return FALSE;
+	return gViewerKeyboard.handleKeyUp(key, mask);
 }
 
-
 void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
 {
 	LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true);
@@ -2542,6 +2541,41 @@ void LLViewerWindow::draw()
 //#endif
 }
 
+// Takes a single keydown event, usually when UI is visible
+BOOL LLViewerWindow::handleKeyUp(KEY key, MASK mask)
+{
+	if (gFocusMgr.getKeyboardFocus()
+		&& !(mask & (MASK_CONTROL | MASK_ALT))
+		&& !gFocusMgr.getKeystrokesOnly())
+	{
+		// We have keyboard focus, and it's not an accelerator
+		if (key < 0x80)
+		{
+			// Not a special key, so likely (we hope) to generate a character.  Let it fall through to character handler first.
+			return (gFocusMgr.getKeyboardFocus() != NULL);
+		}
+	}
+
+	LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
+	if (keyboard_focus)
+	{
+		if (keyboard_focus->handleKeyUp(key, mask, FALSE))
+		{
+			LL_DEBUGS() << "LLviewerWindow::handleKeyUp - in 'traverse up' - no loops seen... just called keyboard_focus->handleKeyUp an it returned true" << LL_ENDL;
+			LLViewerEventRecorder::instance().logKeyEvent(key, mask);
+			return TRUE;
+		}
+		else {
+			LL_DEBUGS() << "LLviewerWindow::handleKeyUp - in 'traverse up' - no loops seen... just called keyboard_focus->handleKeyUp an it returned FALSE" << LL_ENDL;
+		}
+	}
+
+	// don't pass keys on to world when something in ui has focus
+	return gFocusMgr.childHasKeyboardFocus(mRootView)
+		|| LLMenuGL::getKeyboardMode()
+		|| (gMenuBarView && gMenuBarView->getHighlightedItem() && gMenuBarView->getHighlightedItem()->isActive());
+}
+
 // Takes a single keydown event, usually when UI is visible
 BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
 {
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 7fde52d4e1..dac6328eaa 100755
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -314,7 +314,8 @@ public:
 	LLView*			getHintHolder() { return mHintHolder.get(); }
 	LLView*			getLoginPanelHolder() { return mLoginPanelHolder.get(); }
 	BOOL			handleKey(KEY key, MASK mask);
-	void			handleScrollWheel	(S32 clicks);
+	BOOL			handleKeyUp(KEY key, MASK mask);
+	void			handleScrollWheel(S32 clicks);
 
 	// add and remove views from "popup" layer
 	void			addPopup(LLView* popup);
-- 
cgit v1.2.3