Index: binaries/data/config/default.cfg
===================================================================
--- binaries/data/config/default.cfg	(revision 9644)
+++ binaries/data/config/default.cfg	(working copy)
@@ -129,6 +129,7 @@
 hotkey.console.toggle = BackQuote, F9       ; Open/close console
 hotkey.console.copy = "Ctrl+C"              ; Copy from console to clipboard
 hotkey.console.paste = "Ctrl+V"             ; Paste clipboard to console
+hotkey.console.cut = "Ctrl+X"               ; Cut the selected text and copy it to the clipboard
 
 ; > ENTITY SELECTION
 hotkey.selection.add = Shift                ; Add units to selection
@@ -186,6 +187,12 @@
 ; > HOTKEYS ONLY
 hotkey.chat = Return                        ; Toggle chat window
 
+; > GUI TEXTBOX HOTKEYS
+hotkey.text.delete.word.left = "Ctrl+Backspace"    ; Used in text input boxes to delete word to the left of cursor
+hotkey.text.delete.word.right = "Ctrl+Del"         ; Used in text input boxes to delete word to the right of cursor
+hotkey.text.move.word.left = "Ctrl+LeftArrow"      ; Move cursor to start of word to the left of cursor
+hotkey.text.move.word.right = "Ctrl+RightArrow"    ; Move cursor to start of word to the left of cursor
+
 ; > PROFILER
 hotkey.profile.toggle = "F11"               ; Enable/disable real-time profiler
 hotkey.profile.save = "Shift+F11"           ; Save current profiler data to logs/profile.txt
Index: source/gui/CInput.cpp
===================================================================
--- source/gui/CInput.cpp	(revision 9644)
+++ source/gui/CInput.cpp	(working copy)
@@ -34,6 +34,7 @@
 #include "ps/CLogger.h"
 #include "ps/Globals.h"
 
+#include <sstream>
 
 //-------------------------------------------------------------------
 //  Constructor / Destructor
@@ -70,49 +71,30 @@
 {
 	ENSURE(m_iBufferPos != -1);
 
-	// Since the GUI framework doesn't handle to set settings
-	//  in Unicode (CStrW), we'll simply retrieve the actual
-	//  pointer and edit that.
-	CStrW *pCaption = (CStrW*)m_Settings["caption"].m_pSetting;
-
 	if (ev->ev.type == SDL_HOTKEYDOWN)
 	{
-		std::string hotkey = static_cast<const char*>(ev->ev.user.data1);
-		if (hotkey == "console.paste")
-		{
-			wchar_t* text = sys_clipboard_get();
-			if (text)
-			{
-				if (m_iBufferPos == (int)pCaption->length())
-					*pCaption += text;
-				else
-					*pCaption = pCaption->Left(m_iBufferPos) + text + 
-					pCaption->Right((long) pCaption->length()-m_iBufferPos);
-
-				UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos+1);
-
-				m_iBufferPos += (int)wcslen(text);
-
-				sys_clipboard_free(text);
-			}
-
-			return IN_HANDLED;
-		}
+	    return(ManuallyHandleHotkeyEvent(ev));
 	}
 	else if (ev->ev.type == SDL_KEYDOWN)
 	{
+		// Since the GUI framework doesn't handle to set settings
+		//  in Unicode (CStrW), we'll simply retrieve the actual
+		//  pointer and edit that.
+		CStrW *pCaption = (CStrW*)m_Settings["caption"].m_pSetting;
+		bool shiftKeyPressed = g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT];
+
 		int szChar = ev->ev.key.keysym.sym;
 		wchar_t cooked = (wchar_t)ev->ev.key.keysym.unicode;
 
 		switch (szChar)
 		{
-			case '\t':
+			case SDLK_TAB: // '\t'
 				/* Auto Complete */
 				// TODO Gee: (2004-09-07) What to do with tab?
 				break;
 
-			case '\b':
-				m_WantedX=0.f;
+			case SDLK_BACKSPACE: // '\b'
+				m_WantedX=0.0f;
 
 				if (SelectingText())
 					DeleteCurSelection();
@@ -120,26 +102,29 @@
 				{
 					m_iBufferPos_Tail = -1;
 
-					if (pCaption->empty() ||
-						m_iBufferPos == 0)
+					if (pCaption->empty() || m_iBufferPos == 0)
+					{
 						break;
-
-					if (m_iBufferPos == (int)pCaption->length())
-						*pCaption = pCaption->Left( (long) pCaption->length()-1);
+					}
 					else
-						*pCaption = pCaption->Left( m_iBufferPos-1 ) + 
-									pCaption->Right( (long) pCaption->length()-m_iBufferPos );
+					{
+						if (m_iBufferPos == (int)pCaption->length())
+							*pCaption = pCaption->Left( (long) pCaption->length()-1);
+						else
+							*pCaption = pCaption->Left( m_iBufferPos-1 ) + 
+										pCaption->Right( (long) pCaption->length()-m_iBufferPos );
 
-					--m_iBufferPos;
+						--m_iBufferPos;
 					
-					UpdateText(m_iBufferPos, m_iBufferPos+1, m_iBufferPos);
+						UpdateText(m_iBufferPos, m_iBufferPos+1, m_iBufferPos);
+					}
 				}
 
 				UpdateAutoScroll();
 				break;
 
 			case SDLK_DELETE:
-				m_WantedX=0.f;
+				m_WantedX=0.0f;
 				// If selection:
 				if (SelectingText())
 				{
@@ -147,14 +132,17 @@
 				}
 				else
 				{
-					if (pCaption->empty() ||
-						m_iBufferPos == (int)pCaption->length())
+					if (pCaption->empty() || m_iBufferPos == (int)pCaption->length())
+					{
 						break;
+					}
+					else
+					{
+						*pCaption = pCaption->Left( m_iBufferPos ) + 
+									pCaption->Right( (long) pCaption->length()-(m_iBufferPos+1) );
 
-					*pCaption = pCaption->Left( m_iBufferPos ) + 
-								pCaption->Right( (long) pCaption->length()-(m_iBufferPos+1) );
-
-					UpdateText(m_iBufferPos, m_iBufferPos+1, m_iBufferPos);
+						UpdateText(m_iBufferPos, m_iBufferPos+1, m_iBufferPos);
+					}
 				}
 
 				UpdateAutoScroll();
@@ -162,7 +150,7 @@
 
 			case SDLK_HOME:
 				// If there's not a selection, we should create one now
-				if (!g_keys[SDLK_RSHIFT] && !g_keys[SDLK_LSHIFT])
+				if (!shiftKeyPressed)
 				{
 					// Make sure a selection isn't created.
 					m_iBufferPos_Tail = -1;
@@ -174,14 +162,14 @@
 				}
 
 				m_iBufferPos = 0;
-				m_WantedX=0.f;
+				m_WantedX=0.0f;
 
 				UpdateAutoScroll();
 				break;
 
 			case SDLK_END:
 				// If there's not a selection, we should create one now
-				if (!g_keys[SDLK_RSHIFT] && !g_keys[SDLK_LSHIFT])
+				if (!shiftKeyPressed)
 				{
 					// Make sure a selection isn't created.
 					m_iBufferPos_Tail = -1;
@@ -193,7 +181,7 @@
 				}
 
 				m_iBufferPos = (long) pCaption->length();
-				m_WantedX=0.f;
+				m_WantedX=0.0f;
 
 				UpdateAutoScroll();
 				break;
@@ -221,25 +209,20 @@
 
 			**/
 			case SDLK_LEFT:
-				// reset m_WantedX, very important
 				m_WantedX=0.f;
 
-				if (g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT] ||
-					!SelectingText())
+				if (shiftKeyPressed || !SelectingText())
 				{
-					// If there's not a selection, we should create one now
-					if (!SelectingText() && !g_keys[SDLK_RSHIFT] && !g_keys[SDLK_LSHIFT])
+					if (!shiftKeyPressed)
 					{
-						// Make sure a selection isn't created.
 						m_iBufferPos_Tail = -1;
 					}
 					else if (!SelectingText())
 					{
-						// Place tail at the current point:
 						m_iBufferPos_Tail = m_iBufferPos;
 					}
 
-					if (m_iBufferPos) 
+					if (m_iBufferPos > 0) 
 						--m_iBufferPos;
 				}
 				else
@@ -254,25 +237,20 @@
 				break;
 
 			case SDLK_RIGHT:
-				m_WantedX=0.f;
+				m_WantedX=0.0f;
 
-				if (g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT] || 
-					!SelectingText())
+				if (shiftKeyPressed || !SelectingText())
 				{
-					// If there's not a selection, we should create one now
-					if (!SelectingText() && !g_keys[SDLK_RSHIFT] && !g_keys[SDLK_LSHIFT])
+					if (!shiftKeyPressed)
 					{
-						// Make sure a selection isn't created.
 						m_iBufferPos_Tail = -1;
 					}
 					else if (!SelectingText())
 					{
-						// Place tail at the current point:
 						m_iBufferPos_Tail = m_iBufferPos;
 					}
 
-
-					if (m_iBufferPos != (int)pCaption->length())
+					if (m_iBufferPos < (int)pCaption->length())
 						++m_iBufferPos;
 				}
 				else
@@ -308,15 +286,12 @@
 			**/
 			case SDLK_UP:
 			{
-				// If there's not a selection, we should create one now
-				if (!g_keys[SDLK_RSHIFT] && !g_keys[SDLK_LSHIFT])
+				if (!shiftKeyPressed)
 				{
-					// Make sure a selection isn't created.
 					m_iBufferPos_Tail = -1;
 				}
 				else if (!SelectingText())
 				{
-					// Place tail at the current point:
 					m_iBufferPos_Tail = m_iBufferPos;
 				}
 
@@ -356,15 +331,12 @@
 
 			case SDLK_DOWN:
 			{
-				// If there's not a selection, we should create one now
-				if (!g_keys[SDLK_RSHIFT] && !g_keys[SDLK_LSHIFT])
+				if (!shiftKeyPressed)
 				{
-					// Make sure a selection isn't created.
 					m_iBufferPos_Tail = -1;
 				}
 				else if (!SelectingText())
 				{
-					// Place tail at the current point:
 					m_iBufferPos_Tail = m_iBufferPos;
 				}
 
@@ -428,7 +400,6 @@
 				}
 			default: //Insert a character
 				{
-				// If there's a selection, delete if first.
 				if (cooked == 0)
 					return IN_PASS; // Important, because we didn't use any key
 
@@ -438,7 +409,7 @@
 				if (max_length != 0 && (int)pCaption->length() >= max_length)
 					break;
 
-				m_WantedX=0.f;
+				m_WantedX=0.0f;
 
 				if (SelectingText())
 					DeleteCurSelection();
@@ -465,6 +436,251 @@
 	return IN_PASS;
 }
 
+
+InReaction CInput::ManuallyHandleHotkeyEvent(const SDL_Event_* ev)
+{
+	CStrW *pCaption = (CStrW*)m_Settings["caption"].m_pSetting;
+	bool shiftKeyPressed = g_keys[SDLK_RSHIFT] || g_keys[SDLK_LSHIFT];
+
+	std::string hotkey = static_cast<const char*>(ev->ev.user.data1);
+	if (hotkey == "console.paste")
+	{
+		m_WantedX=0.0f;
+
+		wchar_t* text = sys_clipboard_get();
+		if (text)
+		{
+			if (m_iBufferPos == (int)pCaption->length())
+				*pCaption += text;
+			else
+				*pCaption = pCaption->Left(m_iBufferPos) + text + 
+				pCaption->Right((long) pCaption->length()-m_iBufferPos);
+
+			UpdateText(m_iBufferPos, m_iBufferPos, m_iBufferPos+1);
+
+			m_iBufferPos += (int)wcslen(text);
+
+			sys_clipboard_free(text);
+		}
+
+		return IN_HANDLED;
+	}
+	else if (hotkey == "console.copy" || hotkey == "console.cut")
+	{
+		m_WantedX=0.0f;
+
+		if (SelectingText())
+		{
+			int virtualFrom;
+			int virtualTo;
+
+			if (m_iBufferPos_Tail >= m_iBufferPos)
+			{
+				virtualFrom = m_iBufferPos;
+				virtualTo = m_iBufferPos_Tail;
+			}
+			else
+			{
+				virtualFrom = m_iBufferPos_Tail;
+				virtualTo = m_iBufferPos;
+			}
+
+			CStrW text = (pCaption->Left(virtualTo)).Right(virtualTo - virtualFrom);
+
+			sys_clipboard_set(&text[0]);
+
+			if (hotkey == "console.cut")
+			{
+				DeleteCurSelection();
+			}
+		}
+
+		return IN_HANDLED;
+	}
+	else if (hotkey == "text.delete.word.left")
+	{
+		m_WantedX=0.0f;
+
+		if (SelectingText())
+		{
+			DeleteCurSelection();
+		}
+		if (!pCaption->empty() && !m_iBufferPos == 0)
+		{
+			m_iBufferPos_Tail = m_iBufferPos;
+			CStrW searchString = pCaption->Left( m_iBufferPos );
+
+			// If we are starting in whitespace, adjust position until we get a non whitespace
+			while (m_iBufferPos > 0)
+			{
+				if (!iswspace(searchString[m_iBufferPos - 1]))
+					break;
+
+				m_iBufferPos--;
+			}
+				
+			// If we end up on a puctuation char we just delete it (treat punct like a word)
+			if (iswpunct(searchString[m_iBufferPos - 1]))
+				m_iBufferPos--;
+			else
+			{
+				// Now we are on a non white space character, adjust position to char after next whitespace char is found
+				while (m_iBufferPos > 0)
+				{
+					if (iswspace(searchString[m_iBufferPos - 1]) || iswpunct(searchString[m_iBufferPos - 1]))
+						break;
+
+					m_iBufferPos--;
+				}
+			}
+
+			DeleteCurSelection();
+		}
+		return IN_HANDLED;
+	} 
+	else if (hotkey == "text.delete.word.right")
+	{
+		m_WantedX=0.0f;
+
+		if (SelectingText())
+		{
+			DeleteCurSelection();
+		}
+		if (!pCaption->empty() && m_iBufferPos < (int)pCaption->length())
+		{
+			// Delete the word to the right of the cursor
+			m_iBufferPos_Tail = m_iBufferPos;
+
+			// Delete chars to the right unit we hit whitespace
+			while (++m_iBufferPos < (int)pCaption->length())
+			{
+				if (iswspace((*pCaption)[m_iBufferPos]) || iswpunct((*pCaption)[m_iBufferPos]))
+					break;
+			}
+
+			// Eliminate any whitespace behind the word we just deleted
+			while (m_iBufferPos < (int)pCaption->length())
+			{
+				if (!iswspace((*pCaption)[m_iBufferPos]))
+					break;
+
+				m_iBufferPos++;
+			}
+			DeleteCurSelection();
+		}
+		return IN_HANDLED;			
+	}
+	else if (hotkey == "text.move.word.left")
+	{
+		m_WantedX=0.0f;
+				
+		if (shiftKeyPressed || !SelectingText())
+		{
+			if (!shiftKeyPressed)
+			{
+				m_iBufferPos_Tail = -1;
+			}
+			else if (!SelectingText())
+			{
+				m_iBufferPos_Tail = m_iBufferPos;
+			}
+
+			if (!pCaption->empty() && !m_iBufferPos == 0)
+			{
+				CStrW searchString = pCaption->Left( m_iBufferPos );
+
+				// If we are starting in whitespace, adjust position until we get a non whitespace
+				while (m_iBufferPos > 0)
+				{
+					if (!iswspace(searchString[m_iBufferPos - 1]))
+						break;
+
+					m_iBufferPos--;
+				}
+				
+				// If we end up on a puctuation char we just select it (treat punct like a word)
+				if (iswpunct(searchString[m_iBufferPos - 1]))
+					m_iBufferPos--;
+				else
+				{
+					// Now we are on a non white space character, adjust position to char after next whitespace char is found
+					while (m_iBufferPos > 0)
+					{
+						if (iswspace(searchString[m_iBufferPos - 1]) || iswpunct(searchString[m_iBufferPos - 1]))
+							break;
+
+						m_iBufferPos--;
+					}
+				}
+			}
+		}
+		else
+		{
+			if (m_iBufferPos_Tail < m_iBufferPos)
+				m_iBufferPos = m_iBufferPos_Tail;
+
+			m_iBufferPos_Tail = -1;
+		}
+
+		UpdateAutoScroll();
+
+		return IN_HANDLED;
+	}
+	else if (hotkey == "text.move.word.right")
+	{
+		m_WantedX=0.0f;
+
+		if (shiftKeyPressed || !SelectingText())
+		{
+			if (!shiftKeyPressed)
+			{
+				m_iBufferPos_Tail = -1;
+			}
+			else if (!SelectingText())
+			{
+				m_iBufferPos_Tail = m_iBufferPos;
+			}
+
+			if (!pCaption->empty() && m_iBufferPos < (int)pCaption->length())
+			{
+				CStrW searchString = *pCaption;
+
+				// Select chars to the right until we hit whitespace
+				while (++m_iBufferPos < (int)pCaption->length())
+				{
+					if (iswspace((*pCaption)[m_iBufferPos]) || iswpunct((*pCaption)[m_iBufferPos]))
+						break;
+				}
+
+				// Also select any whitespace following the word we just selected
+				while (m_iBufferPos < (int)pCaption->length())
+				{
+					if (!iswspace((*pCaption)[m_iBufferPos]))
+						break;
+
+					m_iBufferPos++;
+				}
+			}
+		}
+		else
+		{
+			if (m_iBufferPos_Tail > m_iBufferPos)
+				m_iBufferPos = m_iBufferPos_Tail;
+
+			m_iBufferPos_Tail = -1;
+		}			
+
+		UpdateAutoScroll();
+
+		return IN_HANDLED;
+	}
+	else
+	{
+		return IN_PASS;
+	}
+}
+
+
 void CInput::HandleMessage(SGUIMessage &Message)
 {
 	// TODO Gee:
@@ -560,11 +776,106 @@
 		
 		UpdateAutoScroll();
 
-		// If we immediately release the button it will just be seen as a click
+		// If we immediately release the  button it will just be seen as a click
 		//  for the user though.
 
 		}break;
 
+	case GUIM_MOUSE_DBLCLICK_LEFT:
+		{
+			CStrW *pCaption = (CStrW*)m_Settings["caption"].m_pSetting;
+			m_iBufferPos = m_iBufferPos_Tail = GetMouseHoveringTextPosition();
+
+			// See if we are clicking over whitespace
+			if (iswspace((*pCaption)[m_iBufferPos]))
+			{
+				// see if we are in a section of whitespace greater than one character
+				if ((m_iBufferPos + 1 < (int) pCaption->length() && iswspace((*pCaption)[m_iBufferPos + 1])) ||
+				    (m_iBufferPos - 1 > 0 && iswspace((*pCaption)[m_iBufferPos - 1])))
+				{
+					//
+					// We are clicking in an area with more than one whitespace character
+					// so we select both the word to the left and then the word to the right
+					//
+					// [1] First the left
+					// skip the whitespace
+					while (m_iBufferPos > 0)
+					{
+						if (!iswspace((*pCaption)[m_iBufferPos - 1]))
+							break;
+
+						m_iBufferPos--;
+					}
+					// now go until we hit white space or punctuation
+					while (m_iBufferPos > 0)
+					{
+						if (iswspace((*pCaption)[m_iBufferPos - 1]))
+							break;
+
+						m_iBufferPos--;
+
+						if (iswpunct((*pCaption)[m_iBufferPos]))
+							break;
+					}
+
+					// [2] Then the right
+					// go right until we are not in whitespace
+					while (++m_iBufferPos_Tail < (int)pCaption->length())
+					{
+						if (!iswspace((*pCaption)[m_iBufferPos_Tail]))
+							break;
+					}
+					// now go to the right until we hit whitespace or punctuation
+					while (++m_iBufferPos_Tail < (int)pCaption->length())
+					{
+						if (iswspace((*pCaption)[m_iBufferPos_Tail]) || iswpunct((*pCaption)[m_iBufferPos_Tail]))
+							break;
+					}
+				}
+				else
+				{
+					// single whitespace so select word to the right
+					while (++m_iBufferPos_Tail < (int)pCaption->length())
+					{
+						if (!iswspace((*pCaption)[m_iBufferPos_Tail]))
+							break;
+					}
+
+					// Don't include the leading whitespace
+					m_iBufferPos = m_iBufferPos_Tail;
+
+					// now go to the right until we hit whitespace or punctuation
+					while (++m_iBufferPos_Tail < (int)pCaption->length())
+					{
+						if (iswspace((*pCaption)[m_iBufferPos_Tail]) || iswpunct((*pCaption)[m_iBufferPos_Tail]))
+							break;
+					}
+				}
+			}
+			else
+			{
+				// clicked on non-whitespace so select current word
+				// go until we hit white space or punctuation
+				while (m_iBufferPos > 0)
+				{
+					if (iswspace((*pCaption)[m_iBufferPos - 1]))
+						break;
+
+					m_iBufferPos--;
+
+					if (iswpunct((*pCaption)[m_iBufferPos]))
+						break;
+				}
+				// go to the right until we hit whitespace or punctuation
+				while (++m_iBufferPos_Tail < (int)pCaption->length())
+				{
+					if (iswspace((*pCaption)[m_iBufferPos_Tail]) || iswpunct((*pCaption)[m_iBufferPos_Tail]))
+						break;
+				}
+			}
+		}
+		break;
+
 	case GUIM_MOUSE_RELEASE_LEFT:
 		if (m_SelectingText)
 		{
@@ -1428,7 +1739,7 @@
 		return 0;
 
 	// Return position
-	int RetPosition;
+	int retPosition;
 
 	float buffer_zone;
 	bool multiline;
@@ -1493,20 +1804,19 @@
 	}
 
 	//m_iBufferPos = m_CharacterPositions.get.m_ListStart;
-	RetPosition = current->m_ListStart;
+	retPosition = current->m_ListStart;
 	
 	// Okay, now loop through the glyphs to find the appropriate X position
 	float dummy;
-	RetPosition += GetXTextPosition(current, mouse.x, dummy);
+	retPosition += GetXTextPosition(current, mouse.x, dummy);
 
-	return RetPosition;
+	return retPosition;
 }
 
 // Does not process horizontal scrolling, 'x' must be modified before inputted.
 int CInput::GetXTextPosition(const std::list<SRow>::iterator &current, const float &x, float &wanted)
 {
-	int Ret=0;
-
+	int ret=0;
 	float previous=0.f;
 	int i=0;
 
@@ -1517,9 +1827,9 @@
 		if (*it >= x)
 		{
 			if (x - previous >= *it - x)
-				Ret += i+1;
+				ret += i+1;
 			else
-				Ret += i;
+				ret += i;
 
 			break;
 		}
@@ -1529,39 +1839,40 @@
 	//  character of that line.
 	if (i == (int)current->m_ListOfX.size())
 	{
-		Ret += i;
+		ret += i;
 		wanted = x;
 	}
 	else wanted = 0.f;
 
-	return Ret;
+	return ret;
 }
 
 void CInput::DeleteCurSelection()
 {
 	CStrW *pCaption = (CStrW*)m_Settings["caption"].m_pSetting;
 
-	int VirtualFrom, VirtualTo;
+	int virtualFrom;
+	int virtualTo;
 
 	if (m_iBufferPos_Tail >= m_iBufferPos)
 	{
-		VirtualFrom = m_iBufferPos;
-		VirtualTo = m_iBufferPos_Tail;
+		virtualFrom = m_iBufferPos;
+		virtualTo = m_iBufferPos_Tail;
 	}
 	else
 	{
-		VirtualFrom = m_iBufferPos_Tail;
-		VirtualTo = m_iBufferPos;
+		virtualFrom = m_iBufferPos_Tail;
+		virtualTo = m_iBufferPos;
 	}
 
-	*pCaption = pCaption->Left( VirtualFrom ) + 
-				pCaption->Right( (long) pCaption->length()-(VirtualTo) );
+	*pCaption = pCaption->Left( virtualFrom ) + 
+				pCaption->Right( (long) pCaption->length() - (virtualTo) );
 
-	UpdateText(VirtualFrom, VirtualTo, VirtualFrom);
+	UpdateText(virtualFrom, virtualTo, virtualFrom);
 
 	// Remove selection
 	m_iBufferPos_Tail = -1;
-	m_iBufferPos = VirtualFrom;
+	m_iBufferPos = virtualFrom;
 }
 
 bool CInput::SelectingText() const
Index: source/gui/CInput.h
===================================================================
--- source/gui/CInput.h	(revision 9644)
+++ source/gui/CInput.h	(working copy)
@@ -97,6 +97,11 @@
 	virtual InReaction ManuallyHandleEvent(const SDL_Event_* ev);
 
 	/**
+	 * Handle hotkey events (MannuallHandleEvent call this for Hotkeys)
+	 */
+	virtual InReaction ManuallyHandleHotkeyEvent(const SDL_Event_* ev);
+
+	/**
 	 * @see IGUIObject#UpdateCachedSize()
 	 */
 	virtual void UpdateCachedSize();
Index: source/lib/sysdep/os/win/wclipboard.cpp
===================================================================
--- source/lib/sysdep/os/win/wclipboard.cpp	(revision 9644)
+++ source/lib/sysdep/os/win/wclipboard.cpp	(working copy)
@@ -30,7 +30,7 @@
 static Status SetClipboardText(const wchar_t* text, HGLOBAL* hMem)
 {
 	const size_t numChars = wcslen(text);
-	*hMem = GlobalAlloc(GMEM_MOVEABLE, (numChars+1) * sizeof(wchar_t));
+	*hMem = GlobalAlloc(GHND | GMEM_SHARE, (numChars + 1) * sizeof(wchar_t));
 	if(!*hMem)
 		WARN_RETURN(ERR::NO_MEM);
 
@@ -50,9 +50,36 @@
 // "copy" text into the clipboard. replaces previous contents.
 Status sys_clipboard_set(const wchar_t* text)
 {
+	//
 	// note: MSDN claims that the window handle must not be 0;
 	// that does actually work on WinXP, but we'll play it safe.
-	if(!OpenClipboard(wutil_AppWindow()))
+	//
+	// Update (6/22/2011):
+	// -------------------------------------------------
+	// DOESNT WORK --> HWND hWnd = wutil_AppWindow();
+	// -------------------------------------------------
+	//
+	// Using the above handle would allow you to open the clipboard
+	// but then upon trying to read from clipboard you would always
+	// get the error "The Handle Is Invalid" when calling GlobalLock
+	// on the clipboard memory handle.  Strangely enough you could
+	// copy and paste between other applications, but not within
+	// this application.
+	//
+	// hWnd = NULL does work.
+	//
+	// From MSDN: A handle to the window to be associated with the 
+	// open clipboard. If this parameter is NULL, the open clipboard 
+	// is associated with the current task.
+	//
+	// This works with text, but may need to revisited if we want to
+	// cut and paste other things like graphics other digital assets.
+	// In that case we may need to add support to the AppWindow for
+	// processing WM_RENDERFORMAT and WM_RENDERALLFORMATS it has to 
+	// do with some lazy update logic in the clipboard.
+	//
+	HWND hWnd = NULL;
+	if(!OpenClipboard(hWnd))
 		WARN_RETURN(ERR::FAIL);
 	EmptyClipboard();
 
@@ -65,6 +92,11 @@
 	// freed until after CloseClipboard. however, GlobalFree still fails
 	// after the successful completion of both. we'll leave it in to avoid
 	// memory leaks, but ignore its return value.
+	//
+	// Update (6/22/2011):
+	// This is working fine now, GlobalFree is returning null indicating 
+	// that it was successful.  I will leave the message for historic and
+	// debugging purposes since the clipboard is a bit temperamental.
 	(void)GlobalFree(hMem);
 
 	return ret;
@@ -74,6 +106,9 @@
 static wchar_t* CopyClipboardContents()
 {
 	// Windows NT/2000+ auto convert UNICODETEXT <-> TEXT
+	if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
+		return 0;
+
 	HGLOBAL hMem = GetClipboardData(CF_UNICODETEXT);
 	if(!hMem)
 		return 0;
@@ -91,21 +126,23 @@
 	return text;
 }
 
-// allow "pasting" from clipboard. returns the current contents if they
+// Allow "pasting" from clipboard. returns the current contents if they
 // can be represented as text, otherwise 0.
-// when it is no longer needed, the returned pointer must be freed via
+// When it is no longer needed, the returned pointer must be freed via
 // sys_clipboard_free. (NB: not necessary if zero, but doesn't hurt)
 wchar_t* sys_clipboard_get()
 {
 	if(!OpenClipboard(wutil_AppWindow()))
 		return 0;
+		
 	wchar_t* const ret = CopyClipboardContents();
 	CloseClipboard();
+
 	return ret;
 }
 
 
-// frees memory used by <copy>, which must have been returned by
+// Frees memory used by <copy>, which must have been returned by
 // sys_clipboard_get. see note above.
 Status sys_clipboard_free(wchar_t* text)
 {

