Bladeren bron

Started work on keyboard events

Marko Pintera 12 jaren geleden
bovenliggende
commit
cd38620ea7

+ 2 - 0
BansheeEngine/BansheeEngine.vcxproj

@@ -152,6 +152,7 @@
     <ClInclude Include="Include\BsGUIArea.h" />
     <ClInclude Include="Include\BsGUIButton.h" />
     <ClInclude Include="Include\BsGUIInputBox.h" />
+    <ClInclude Include="Include\BsGUIKeyEvent.h" />
     <ClInclude Include="Include\BsGUILayoutOptions.h" />
     <ClInclude Include="Include\BsGUILayoutX.h" />
     <ClInclude Include="Include\BsGUILayout.h" />
@@ -194,6 +195,7 @@
     <ClCompile Include="Source\BsGUIButton.cpp" />
     <ClCompile Include="Source\BsGUIElement.cpp" />
     <ClCompile Include="Source\BsGUIInputBox.cpp" />
+    <ClCompile Include="Source\BsGUIKeyEvent.cpp" />
     <ClCompile Include="Source\BsGUILabel.cpp" />
     <ClCompile Include="Source\BsGUILayout.cpp" />
     <ClCompile Include="Source\BsGUILayoutY.cpp" />

+ 6 - 0
BansheeEngine/BansheeEngine.vcxproj.filters

@@ -153,6 +153,9 @@
     <ClInclude Include="Include\BsGUIInputBox.h">
       <Filter>Header Files\GUI</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsGUIKeyEvent.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsGUIElement.cpp">
@@ -254,5 +257,8 @@
     <ClCompile Include="Source\BsGUIMouseEvent.cpp">
       <Filter>Source Files\GUI</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsGUIKeyEvent.cpp">
+      <Filter>Source Files\GUI</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 4 - 4
BansheeEngine/Include/BsGUIButton.h

@@ -11,8 +11,8 @@ namespace BansheeEngine
 	public:
 		static const CM::String& getGUITypeName();
 
-		static GUIButton* create(GUIWidget& parent, const CM::String& text, const GUIElementStyle* style = nullptr);
-		static GUIButton* create(GUIWidget& parent, const CM::String& text, const GUILayoutOptions& layoutOptions, const GUIElementStyle* style = nullptr);
+		static GUIButton* create(GUIWidget& parent, const CM::WString& text, const GUIElementStyle* style = nullptr);
+		static GUIButton* create(GUIWidget& parent, const CM::WString& text, const GUILayoutOptions& layoutOptions, const GUIElementStyle* style = nullptr);
 	protected:
 		~GUIButton();
 
@@ -52,9 +52,9 @@ namespace BansheeEngine
 		CM::UINT32 mNumImageRenderElements;
 
 		IMAGE_SPRITE_DESC mImageDesc;
-		CM::String mText;
+		CM::WString mText;
 
-		GUIButton(GUIWidget& parent, const GUIElementStyle* style, const CM::String& text, const GUILayoutOptions& layoutOptions);
+		GUIButton(GUIWidget& parent, const GUIElementStyle* style, const CM::WString& text, const GUILayoutOptions& layoutOptions);
 
 		virtual bool mouseEvent(const GUIMouseEvent& ev);
 	};

+ 5 - 1
BansheeEngine/Include/BsGUIElement.h

@@ -10,7 +10,7 @@ namespace BansheeEngine
 	class BS_EXPORT GUIElement
 	{
 	public:
-		GUIElement(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions);
+		GUIElement(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions, bool acceptsKeyboardFocus = false);
 		virtual ~GUIElement();
 
 		/**
@@ -74,6 +74,7 @@ namespace BansheeEngine
 		void updateRenderElements();
 
 		virtual bool mouseEvent(const GUIMouseEvent& ev);
+		virtual bool keyEvent(const GUIKeyEvent& ev);
 
 		static void destroy(GUIElement* element);
 
@@ -90,6 +91,7 @@ namespace BansheeEngine
 		void _setWidth(CM::UINT32 width);
 		void _setHeight(CM::UINT32 height);
 		void _setClipRect(const CM::Rect& clipRect);
+		virtual void _setFocus(bool focus) {}
 
 		CM::UINT32 _getWidth() const { return mWidth; }
 		CM::UINT32 _getHeight() const { return mHeight; }
@@ -103,6 +105,7 @@ namespace BansheeEngine
 		GUIWidget& _getParentWidget() const { return mParent; }
 		bool _isDirty() const { return mIsDirty; }
 		virtual bool _isInBounds(const CM::Int2 position) const;
+		bool _acceptsKeyboardFocus() const { return mAcceptsKeyboardFocus; }
 
 		const GUILayoutOptions& _getLayoutOptions() const { return mLayoutOptions; }
 
@@ -126,6 +129,7 @@ namespace BansheeEngine
 		CM::Rect mBounds;
 
 		bool mIsDirty;
+		bool mAcceptsKeyboardFocus;
 		CM::UINT32 mDepth;
 		CM::Int2 mOffset;
 		CM::UINT32 mWidth, mHeight;

+ 3 - 1
BansheeEngine/Include/BsGUIInputBox.h

@@ -46,6 +46,7 @@ namespace BansheeEngine
 		virtual CM::UINT32 _getOptimalHeight() const;
 
 		virtual CM::UINT32 _getRenderElementDepth(CM::UINT32 renderElementIdx) const;
+		virtual void _setFocus(bool focus);
 	private:
 		ImageSprite* mImageSprite;
 		TextSprite* mTextSprite;
@@ -54,10 +55,11 @@ namespace BansheeEngine
 		bool mDragInProgress;
 
 		IMAGE_SPRITE_DESC mImageDesc;
-		CM::String mText;
+		CM::WString mText;
 
 		GUIInputBox(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions);
 
 		virtual bool mouseEvent(const GUIMouseEvent& ev);
+		virtual bool keyEvent(const GUIKeyEvent& ev);
 	};
 }

+ 35 - 0
BansheeEngine/Include/BsGUIKeyEvent.h

@@ -0,0 +1,35 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "CmInputHandler.h"
+#include "CmInt2.h"
+
+namespace BansheeEngine
+{
+	enum class GUIKeyEventType
+	{
+		KeyUp,
+		KeyDown,
+		TextInput
+	};
+
+	class BS_EXPORT GUIKeyEvent
+	{
+	public:
+		GUIKeyEvent();
+
+		GUIKeyEventType getType() const { return mType; }
+		CM::KeyCode getKey() const { return mKey; }
+		const CM::WString& getInputString() const { return mInputString; }
+	private:
+		friend class GUIManager;
+
+		GUIKeyEventType mType;
+		CM::KeyCode mKey;
+		CM::WString mInputString;
+
+		void setKeyDownData(CM::KeyCode key);
+		void setKeyUpData(CM::KeyCode key);
+		void setTextInputData(const CM::WString& string);
+	};
+}

+ 4 - 4
BansheeEngine/Include/BsGUILabel.h

@@ -11,8 +11,8 @@ namespace BansheeEngine
 	public:
 		static const CM::String& getGUITypeName();
 
-		static GUILabel* create(GUIWidget& parent, const CM::String& text, const GUIElementStyle* style = nullptr);
-		static GUILabel* create(GUIWidget& parent, const CM::String& text, const GUILayoutOptions& layoutOptions, const GUIElementStyle* style = nullptr);
+		static GUILabel* create(GUIWidget& parent, const CM::WString& text, const GUIElementStyle* style = nullptr);
+		static GUILabel* create(GUIWidget& parent, const CM::WString& text, const GUILayoutOptions& layoutOptions, const GUIElementStyle* style = nullptr);
 
 		void setText(const CM::String& text);
 
@@ -49,10 +49,10 @@ namespace BansheeEngine
 		virtual CM::UINT32 _getOptimalHeight() const;
 	private:
 		TextSprite* mTextSprite;
-		CM::String mText;
+		CM::WString mText;
 
 		TEXT_SPRITE_DESC mDesc;
 		
-		GUILabel(GUIWidget& parent, const GUIElementStyle* style, const CM::String& text, const GUILayoutOptions& layoutOptions);
+		GUILabel(GUIWidget& parent, const GUIElementStyle* style, const CM::WString& text, const GUILayoutOptions& layoutOptions);
 	};
 }

+ 6 - 0
BansheeEngine/Include/BsGUIManager.h

@@ -2,6 +2,7 @@
 
 #include "BsPrerequisites.h"
 #include "BsGUIMouseEvent.h"
+#include "BsGUIKeyEvent.h"
 #include "CmModule.h"
 #include "CmInputHandler.h"
 #include "CmDeferredRenderContextFwd.h"
@@ -48,11 +49,16 @@ namespace BansheeEngine
 		GUIElement* mActiveElement;
 		CM::UINT32 mActiveMouseButton;
 
+		// Element and widget that currently have the keyboard focus
+		GUIWidget* mKeyboardFocusWidget;
+		GUIElement* mKeyboardFocusElement;
+
 		bool mSeparateMeshesByWidget;
 		bool mLastFrameButtonState[CM::MB_Count];
 		CM::Int2 mLastCursorLocalPos;
 
 		GUIMouseEvent mMouseEvent;
+		GUIKeyEvent mKeyEvent;
 
 		void updateMeshes();
 		void updateInput();

+ 12 - 10
BansheeEngine/Include/BsGUIMouseEvent.h

@@ -30,22 +30,24 @@ namespace BansheeEngine
 		CM::Int2 getDragAmount() const { return mDragAmount; }
 		bool isButtonDown(CM::MouseButton button) const { return mButtonStates[(int)button]; }
 		GUIElement* getMouseOverElement() const { return mMouseOverElement; }
-
-		void _setMouseOverData(GUIElement* mouseOverElement, const CM::Int2& position);
-		void _setMouseOutData(GUIElement* mouseOverElement, const CM::Int2& position);
-		void _setMouseMoveData(GUIElement* mouseOverElement, const CM::Int2& position);
-		void _setMouseUpData(GUIElement* mouseOverElement, const CM::Int2& position, CM::MouseButton button);
-		void _setMouseDownData(GUIElement* mouseOverElement, const CM::Int2& position, CM::MouseButton button);
-
-		void _setMouseDragData(GUIElement* mouseOverElement, const CM::Int2& position, const CM::Int2& dragAmount);
-		void _setMouseDragStartData(GUIElement* mouseOverElement, const CM::Int2& position);
-		void _setMouseDragEndData(GUIElement* mouseOverElement, const CM::Int2& position);
 	private:
+		friend class GUIManager;
+
 		CM::Int2 mPosition;
 		CM::Int2 mDragAmount;
 		GUIMouseEventType mType;
 		CM::MouseButton mButton;
 		bool mButtonStates[CM::MB_Count];
 		GUIElement* mMouseOverElement;
+
+		void setMouseOverData(GUIElement* mouseOverElement, const CM::Int2& position);
+		void setMouseOutData(GUIElement* mouseOverElement, const CM::Int2& position);
+		void setMouseMoveData(GUIElement* mouseOverElement, const CM::Int2& position);
+		void setMouseUpData(GUIElement* mouseOverElement, const CM::Int2& position, CM::MouseButton button);
+		void setMouseDownData(GUIElement* mouseOverElement, const CM::Int2& position, CM::MouseButton button);
+
+		void setMouseDragData(GUIElement* mouseOverElement, const CM::Int2& position, const CM::Int2& dragAmount);
+		void setMouseDragStartData(GUIElement* mouseOverElement, const CM::Int2& position);
+		void setMouseDragEndData(GUIElement* mouseOverElement, const CM::Int2& position);
 	};
 }

+ 4 - 4
BansheeEngine/Include/BsGUIToggle.h

@@ -11,8 +11,8 @@ namespace BansheeEngine
 	public:
 		static const CM::String& getGUITypeName();
 
-		static GUIToggle* create(GUIWidget& parent, const CM::String& text, const GUIElementStyle* style = nullptr);
-		static GUIToggle* create(GUIWidget& parent, const GUILayoutOptions& layoutOptions, const CM::String& text, const GUIElementStyle* style = nullptr);
+		static GUIToggle* create(GUIWidget& parent, const CM::WString& text, const GUIElementStyle* style = nullptr);
+		static GUIToggle* create(GUIWidget& parent, const GUILayoutOptions& layoutOptions, const CM::WString& text, const GUIElementStyle* style = nullptr);
 	protected:
 		~GUIToggle();
 
@@ -53,9 +53,9 @@ namespace BansheeEngine
 		bool mIsToggled;
 
 		IMAGE_SPRITE_DESC mImageDesc;
-		CM::String mText;
+		CM::WString mText;
 
-		GUIToggle(GUIWidget& parent, const GUIElementStyle* style, const CM::String& text, const GUILayoutOptions& layoutOptions);
+		GUIToggle(GUIWidget& parent, const GUIElementStyle* style, const CM::WString& text, const GUILayoutOptions& layoutOptions);
 
 		virtual bool mouseEvent(const GUIMouseEvent& ev);
 	};

+ 6 - 0
BansheeEngine/Include/BsGUIWidget.h

@@ -52,6 +52,12 @@ namespace BansheeEngine
 		 * 			must be a child of this widget.
 		 */
 		virtual bool _mouseEvent(GUIElement* element, const GUIMouseEvent& ev);
+				
+		/**
+		 * @brief	Forwards the specified key event to the specified element. The element
+		 * 			must be a child of this widget.
+		 */
+		virtual bool _keyEvent(GUIElement* element, const GUIKeyEvent& ev);
 	protected:
 		friend class CM::SceneObject;
 		friend class GUIElement;

+ 1 - 0
BansheeEngine/Include/BsPrerequisites.h

@@ -38,6 +38,7 @@ namespace BansheeEngine
 	class GUISkin;
 	struct GUIElementStyle;
 	class GUIMouseEvent;
+	class GUIKeyEvent;
 	class GUIArea;
 	class GUILayout;
 	class GUILayoutX;

+ 1 - 1
BansheeEngine/Include/BsTextSprite.h

@@ -28,7 +28,7 @@ namespace BansheeEngine
 		CM::Rect clipRect;
 		SpriteAnchor anchor;
 
-		CM::String text;
+		CM::WString text;
 		CM::HFont font;
 		CM::UINT32 fontSize;
 		TextHorzAlign horzAlign;

+ 3 - 3
BansheeEngine/Source/BsGUIButton.cpp

@@ -18,7 +18,7 @@ namespace BansheeEngine
 		return name;
 	}
 
-	GUIButton::GUIButton(GUIWidget& parent, const GUIElementStyle* style, const String& text, const GUILayoutOptions& layoutOptions)
+	GUIButton::GUIButton(GUIWidget& parent, const GUIElementStyle* style, const WString& text, const GUILayoutOptions& layoutOptions)
 		:GUIElement(parent, style, layoutOptions), mText(text), mNumImageRenderElements(0)
 	{
 		mImageSprite = cm_new<ImageSprite, PoolAlloc>();
@@ -44,7 +44,7 @@ namespace BansheeEngine
 		cm_delete<PoolAlloc>(mImageSprite);
 	}
 
-	GUIButton* GUIButton::create(GUIWidget& parent, const String& text, const GUIElementStyle* style)
+	GUIButton* GUIButton::create(GUIWidget& parent, const WString& text, const GUIElementStyle* style)
 	{
 		if(style == nullptr)
 		{
@@ -55,7 +55,7 @@ namespace BansheeEngine
 		return new (cm_alloc<GUIButton, PoolAlloc>()) GUIButton(parent, style, text, getDefaultLayoutOptions(style));
 	}
 
-	GUIButton* GUIButton::create(GUIWidget& parent, const String& text, const GUILayoutOptions& layoutOptions, const GUIElementStyle* style)
+	GUIButton* GUIButton::create(GUIWidget& parent, const WString& text, const GUILayoutOptions& layoutOptions, const GUIElementStyle* style)
 	{
 		if(style == nullptr)
 		{

+ 8 - 2
BansheeEngine/Source/BsGUIElement.cpp

@@ -8,8 +8,9 @@ using namespace CamelotFramework;
 
 namespace BansheeEngine
 {
-	GUIElement::GUIElement(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions)
-		:mParent(parent), mIsDirty(true), mParentLayout(nullptr), mLayoutOptions(layoutOptions), mWidth(0), mHeight(0), mDepth(0), mStyle(style)
+	GUIElement::GUIElement(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions, bool acceptsKeyboardFocus)
+		:mParent(parent), mIsDirty(true), mParentLayout(nullptr), mLayoutOptions(layoutOptions), mWidth(0), mHeight(0), mDepth(0), mStyle(style),
+		mAcceptsKeyboardFocus(acceptsKeyboardFocus)
 	{
 		mParent.registerElement(this);
 	}
@@ -49,6 +50,11 @@ namespace BansheeEngine
 		return false;
 	}
 
+	bool GUIElement::keyEvent(const GUIKeyEvent& ev)
+	{
+		return false;
+	}
+
 	void GUIElement::_setWidgetDepth(UINT8 depth) 
 	{ 
 		mDepth |= depth << 24; 

+ 29 - 0
BansheeEngine/Source/BsGUIInputBox.cpp

@@ -5,6 +5,7 @@
 #include "BsSpriteTexture.h"
 #include "BsTextSprite.h"
 #include "BsGUILayoutOptions.h"
+#include "BsGUIKeyEvent.h"
 #include "BsGUIMouseEvent.h"
 #include "CmTexture.h"
 #include "CmCursor.h"
@@ -229,4 +230,32 @@ namespace BansheeEngine
 
 		return false;
 	}
+
+	bool GUIInputBox::keyEvent(const GUIKeyEvent& ev)
+	{
+		if(ev.getType() == GUIKeyEventType::TextInput)
+		{
+			// TODO - How are backspace, caps and enter handled?
+			mText += ev.getInputString();
+			markAsDirty();
+
+			return true;
+		}
+
+		return false;
+	}
+
+	void GUIInputBox::_setFocus(bool focus)
+	{
+		if(focus)
+		{
+			mImageDesc.texture = mStyle->focused.texture;
+			markAsDirty();
+		}
+		else
+		{
+			mImageDesc.texture = mStyle->normal.texture;
+			markAsDirty();
+		}
+	}
 }

+ 33 - 0
BansheeEngine/Source/BsGUIKeyEvent.cpp

@@ -0,0 +1,33 @@
+#include "BsGUIKeyEvent.h"
+
+using namespace CamelotFramework;
+
+namespace BansheeEngine
+{
+	GUIKeyEvent::GUIKeyEvent()
+		:mType(GUIKeyEventType::KeyDown), mKey(KC_0)
+	{
+
+	}
+
+	void GUIKeyEvent::setKeyDownData(KeyCode key)
+	{
+		mType = GUIKeyEventType::KeyDown;
+		mKey = key;
+		mInputString = "";
+	}
+
+	void GUIKeyEvent::setKeyUpData(KeyCode key)
+	{
+		mType = GUIKeyEventType::KeyUp;
+		mKey = key;
+		mInputString = "";
+	}
+
+	void GUIKeyEvent::setTextInputData(const WString& string)
+	{
+		mType = GUIKeyEventType::TextInput;
+		mKey = KC_0;
+		mInputString = string;
+	}
+}

+ 4 - 4
BansheeEngine/Source/BsGUILabel.cpp

@@ -10,7 +10,7 @@ using namespace CamelotFramework;
 
 namespace BansheeEngine
 {
-	GUILabel::GUILabel(GUIWidget& parent, const GUIElementStyle* style, const String& text, const GUILayoutOptions& layoutOptions)
+	GUILabel::GUILabel(GUIWidget& parent, const GUIElementStyle* style, const WString& text, const GUILayoutOptions& layoutOptions)
 		:GUIElement(parent, style, layoutOptions), mText(text)
 	{
 		mTextSprite = cm_new<TextSprite, PoolAlloc>();
@@ -98,14 +98,14 @@ namespace BansheeEngine
 		mTextSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, renderElementIdx);
 	}
 
-	void GUILabel::setText(const CM::String& text)
+	void GUILabel::setText(const CM::WString& text)
 	{
 		mDesc.text = text;
 
 		markAsDirty();
 	}
 
-	GUILabel* GUILabel::create(GUIWidget& parent, const String& text, const GUIElementStyle* style)
+	GUILabel* GUILabel::create(GUIWidget& parent, const WString& text, const GUIElementStyle* style)
 	{
 		if(style == nullptr)
 		{
@@ -116,7 +116,7 @@ namespace BansheeEngine
 		return new (cm_alloc<GUILabel, PoolAlloc>()) GUILabel(parent, style, text, getDefaultLayoutOptions(style));
 	}
 
-	GUILabel* GUILabel::create(GUIWidget& parent, const String& text, const GUILayoutOptions& layoutOptions, const GUIElementStyle* style)
+	GUILabel* GUILabel::create(GUIWidget& parent, const WString& text, const GUILayoutOptions& layoutOptions, const GUIElementStyle* style)
 	{
 		if(style == nullptr)
 		{

+ 38 - 9
BansheeEngine/Source/BsGUIManager.cpp

@@ -42,7 +42,7 @@ namespace BansheeEngine
 
 	GUIManager::GUIManager()
 		:mMouseOverElement(nullptr), mMouseOverWidget(nullptr), mSeparateMeshesByWidget(true), mActiveElement(nullptr), 
-		mActiveWidget(nullptr), mActiveMouseButton(0)
+		mActiveWidget(nullptr), mActiveMouseButton(0), mKeyboardFocusElement(nullptr), mKeyboardFocusWidget(nullptr)
 	{
 		for(int i = 0; i < MB_Count; i++)
 			mLastFrameButtonState[i] = false;
@@ -492,7 +492,7 @@ namespace BansheeEngine
 				{
 					Int2 curLocalPos = getWidgetRelativeCursorPos(*mMouseOverWidget);
 
-					mMouseEvent._setMouseOutData(topMostElement, curLocalPos);
+					mMouseEvent.setMouseOutData(topMostElement, curLocalPos);
 					mMouseOverWidget->_mouseEvent(mMouseOverElement, mMouseEvent);
 				}
 			}
@@ -502,7 +502,7 @@ namespace BansheeEngine
 				// Send MouseOver event
 				if(mActiveElement == nullptr || topMostElement == mActiveElement)
 				{
-					mMouseEvent._setMouseOverData(topMostElement, localPos);
+					mMouseEvent.setMouseOverData(topMostElement, localPos);
 					widgetInFocus->_mouseEvent(topMostElement, mMouseEvent);
 				}
 			}
@@ -515,7 +515,7 @@ namespace BansheeEngine
 
 			if(mLastCursorLocalPos != curLocalPos)
 			{
-				mMouseEvent._setMouseDragData(topMostElement, curLocalPos, curLocalPos - mLastCursorLocalPos);
+				mMouseEvent.setMouseDragData(topMostElement, curLocalPos, curLocalPos - mLastCursorLocalPos);
 				mActiveWidget->_mouseEvent(mActiveElement, mMouseEvent);
 
 				mLastCursorLocalPos = curLocalPos;
@@ -528,7 +528,7 @@ namespace BansheeEngine
 				// Send MouseMove event
 				if(mLastCursorLocalPos != localPos)
 				{
-					mMouseEvent._setMouseMoveData(topMostElement, localPos);
+					mMouseEvent.setMouseMoveData(topMostElement, localPos);
 					widgetInFocus->_mouseEvent(topMostElement, mMouseEvent);
 
 					mLastCursorLocalPos = localPos;
@@ -537,6 +537,7 @@ namespace BansheeEngine
 		}
 
 		// Check for MouseDown and MouseUp events.
+		bool isAnyMouseButtonDown = false;
 		for(int i = 0; i < MB_Count; i++)
 		{
 			bool buttonDown = buttonStates[i];
@@ -545,16 +546,18 @@ namespace BansheeEngine
 				// Mouse button is being pressed
 				if(buttonDown)
 				{
+					isAnyMouseButtonDown = true;
+
 					// We only check for mouse down if mouse isn't already being held down, and we are hovering over an element
 					bool acceptMouseDown = mActiveElement == nullptr && topMostElement != nullptr;
 					if(acceptMouseDown)
 					{
-						mMouseEvent._setMouseDownData(topMostElement, localPos, (MouseButton)i);
+						mMouseEvent.setMouseDownData(topMostElement, localPos, (MouseButton)i);
 						widgetInFocus->_mouseEvent(topMostElement, mMouseEvent);
 
 						// DragStart is for all intents and purposes same as mouse down but since I need a DragEnd event, I feel a separate DragStart
 						// event was also needed to make things clearer.
-						mMouseEvent._setMouseDragStartData(topMostElement, localPos);
+						mMouseEvent.setMouseDragStartData(topMostElement, localPos);
 						widgetInFocus->_mouseEvent(topMostElement, mMouseEvent);
 
 						mActiveElement = topMostElement;
@@ -571,7 +574,7 @@ namespace BansheeEngine
 					bool acceptMouseUp = mActiveMouseButton == i && (topMostElement != nullptr && mActiveElement == topMostElement);
 					if(acceptMouseUp)
 					{
-						mMouseEvent._setMouseUpData(topMostElement, localPos, (MouseButton)i);
+						mMouseEvent.setMouseUpData(topMostElement, localPos, (MouseButton)i);
 						widgetInFocus->_mouseEvent(topMostElement, mMouseEvent);
 					}
 
@@ -579,7 +582,7 @@ namespace BansheeEngine
 					bool acceptEndDrag = mActiveMouseButton == i && mActiveElement != nullptr;
 					if(acceptEndDrag)
 					{
-						mMouseEvent._setMouseDragEndData(topMostElement, localPos);
+						mMouseEvent.setMouseDragEndData(topMostElement, localPos);
 						mActiveWidget->_mouseEvent(mActiveElement, mMouseEvent);
 
 						mActiveElement = nullptr;
@@ -594,6 +597,32 @@ namespace BansheeEngine
 
 		mMouseOverElement = topMostElement;
 		mMouseOverWidget = widgetInFocus;
+
+		// Update keyboard focus if user has pressed any mouse button
+		if(isAnyMouseButtonDown)
+		{
+			if(mKeyboardFocusElement != nullptr && mMouseOverElement != mKeyboardFocusElement)
+				mKeyboardFocusElement->_setFocus(false);
+
+			if(mMouseOverElement != nullptr)
+				mMouseOverElement->_setFocus(true);
+
+			mKeyboardFocusElement = mMouseOverElement;
+			mKeyboardFocusWidget = mMouseOverWidget;
+		}
+
+		/************************************************************************/
+		/* 								KEYBOARD EVENTS                    		*/
+		/************************************************************************/
+		if(mKeyboardFocusElement != nullptr)
+		{
+			mKeyEvent = GUIKeyEvent();
+
+			// TODO - Handle KeyUp/KeyDown states
+			
+			mKeyEvent.setTextInputData(gInput().getInputString());
+			mKeyboardFocusWidget->_keyEvent(mKeyboardFocusElement, mKeyEvent);
+		}
 	}
 
 	Int2 GUIManager::getWidgetRelativeCursorPos(const GUIWidget& widget)

+ 8 - 8
BansheeEngine/Source/BsGUIMouseEvent.cpp

@@ -16,7 +16,7 @@ namespace BansheeEngine
 		memcpy(mButtonStates, buttonStates, sizeof(mButtonStates));
 	}
 
-	void GUIMouseEvent::_setMouseOverData(GUIElement* mouseOverElement, const Int2& position)
+	void GUIMouseEvent::setMouseOverData(GUIElement* mouseOverElement, const Int2& position)
 	{
 		mType = GUIMouseEventType::MouseOver;
 		mPosition = position;
@@ -25,7 +25,7 @@ namespace BansheeEngine
 		mDragAmount = Int2();
 	}
 
-	void GUIMouseEvent::_setMouseOutData(GUIElement* mouseOverElement, const Int2& position)
+	void GUIMouseEvent::setMouseOutData(GUIElement* mouseOverElement, const Int2& position)
 	{
 		mType = GUIMouseEventType::MouseOut;
 		mPosition = position;
@@ -34,7 +34,7 @@ namespace BansheeEngine
 		mDragAmount = Int2();
 	}
 
-	void GUIMouseEvent::_setMouseMoveData(GUIElement* mouseOverElement, const Int2& position)
+	void GUIMouseEvent::setMouseMoveData(GUIElement* mouseOverElement, const Int2& position)
 	{
 		mType = GUIMouseEventType::MouseMove;
 		mPosition = position;
@@ -43,7 +43,7 @@ namespace BansheeEngine
 		mDragAmount = Int2();
 	}
 
-	void GUIMouseEvent::_setMouseUpData(GUIElement* mouseOverElement, const Int2& position, MouseButton button)
+	void GUIMouseEvent::setMouseUpData(GUIElement* mouseOverElement, const Int2& position, MouseButton button)
 	{
 		mType = GUIMouseEventType::MouseUp;
 		mPosition = position;
@@ -52,7 +52,7 @@ namespace BansheeEngine
 		mDragAmount = Int2();
 	}
 
-	void GUIMouseEvent::_setMouseDownData(GUIElement* mouseOverElement, const Int2& position, MouseButton button)
+	void GUIMouseEvent::setMouseDownData(GUIElement* mouseOverElement, const Int2& position, MouseButton button)
 	{
 		mType = GUIMouseEventType::MouseDown;
 		mPosition = position;
@@ -61,7 +61,7 @@ namespace BansheeEngine
 		mDragAmount = Int2();
 	}
 
-	void GUIMouseEvent::_setMouseDragData(GUIElement* mouseOverElement, const Int2& position, const Int2& dragAmount)
+	void GUIMouseEvent::setMouseDragData(GUIElement* mouseOverElement, const Int2& position, const Int2& dragAmount)
 	{
 		mType = GUIMouseEventType::MouseDrag;
 		mPosition = position;
@@ -70,7 +70,7 @@ namespace BansheeEngine
 		mDragAmount = dragAmount;
 	}
 
-	void GUIMouseEvent::_setMouseDragStartData(GUIElement* mouseOverElement, const Int2& position)
+	void GUIMouseEvent::setMouseDragStartData(GUIElement* mouseOverElement, const Int2& position)
 	{
 		mType = GUIMouseEventType::MouseDragStart;
 		mPosition = position;
@@ -79,7 +79,7 @@ namespace BansheeEngine
 		mDragAmount = Int2();
 	}
 
-	void GUIMouseEvent::_setMouseDragEndData(GUIElement* mouseOverElement, const Int2& position)
+	void GUIMouseEvent::setMouseDragEndData(GUIElement* mouseOverElement, const Int2& position)
 	{
 		mType = GUIMouseEventType::MouseDragEnd;
 		mPosition = position;

+ 3 - 3
BansheeEngine/Source/BsGUIToggle.cpp

@@ -18,7 +18,7 @@ namespace BansheeEngine
 		return name;
 	}
 
-	GUIToggle::GUIToggle(GUIWidget& parent, const GUIElementStyle* style, const String& text, const GUILayoutOptions& layoutOptions)
+	GUIToggle::GUIToggle(GUIWidget& parent, const GUIElementStyle* style, const WString& text, const GUILayoutOptions& layoutOptions)
 		:GUIElement(parent, style, layoutOptions), mText(text), mNumImageRenderElements(0), mIsToggled(false)
 	{
 		mImageSprite = cm_new<ImageSprite, PoolAlloc>();
@@ -44,7 +44,7 @@ namespace BansheeEngine
 		cm_delete<PoolAlloc>(mImageSprite);
 	}
 
-	GUIToggle* GUIToggle::create(GUIWidget& parent, const String& text, const GUIElementStyle* style)
+	GUIToggle* GUIToggle::create(GUIWidget& parent, const WString& text, const GUIElementStyle* style)
 	{
 		if(style == nullptr)
 		{
@@ -55,7 +55,7 @@ namespace BansheeEngine
 		return new (cm_alloc<GUIToggle, PoolAlloc>()) GUIToggle(parent, style, text, getDefaultLayoutOptions(style));
 	}
 
-	GUIToggle* GUIToggle::create(GUIWidget& parent, const GUILayoutOptions& layoutOptions, const String& text, const GUIElementStyle* style)
+	GUIToggle* GUIToggle::create(GUIWidget& parent, const GUILayoutOptions& layoutOptions, const WString& text, const GUIElementStyle* style)
 	{
 		if(style == nullptr)
 		{

+ 5 - 0
BansheeEngine/Source/BsGUIWidget.cpp

@@ -122,6 +122,11 @@ namespace BansheeEngine
 		return element->mouseEvent(ev);
 	}
 
+	bool GUIWidget::_keyEvent(GUIElement* element, const GUIKeyEvent& ev)
+	{
+		return element->keyEvent(ev);
+	}
+
 	void GUIWidget::registerElement(GUIElement* elem)
 	{
 		assert(elem != nullptr);

+ 5 - 0
CamelotCore/Include/CmInput.h

@@ -38,6 +38,11 @@ namespace CamelotFramework
 		bool isButtonDown(MouseButton button) const;
 		bool isKeyDown(KeyCode keyCode) const;
 
+		/**
+		 * @brief	Gets all the characters inputted since the last frame.
+		 */
+		WString getInputString() const { return mInputHandler->getInputString(); }
+
 	private:
 		InputHandlerPtr mInputHandler;
 

+ 5 - 0
CamelotCore/Include/CmInputHandler.h

@@ -192,5 +192,10 @@ namespace CamelotFramework
 		 * @brief	Called every frame by InputManager. Capture input here if needed.
 		 */
 		virtual void update() {}
+
+		/**
+		 * @brief	Gets all the characters inputted since the last frame.
+		 */
+		virtual const WString& getInputString() const = 0;
 	};
 }

+ 1 - 1
CamelotCore/Include/CmTextUtility.h

@@ -114,6 +114,6 @@ namespace CamelotFramework
 			vector<HTexture>::type mTexturePages;
 		};
 
-		static std::shared_ptr<TextUtility::TextData> getTextData(const String& text, const HFont& font, UINT32 fontSize, UINT32 width = 0, UINT32 height = 0, bool wordWrap = false);
+		static std::shared_ptr<TextUtility::TextData> getTextData(const WString& text, const HFont& font, UINT32 fontSize, UINT32 width = 0, UINT32 height = 0, bool wordWrap = false);
 	};
 }

+ 1 - 1
CamelotCore/Source/CmTextUtility.cpp

@@ -258,7 +258,7 @@ namespace CamelotFramework
 	{
 	}
 
-	std::shared_ptr<TextUtility::TextData> TextUtility::getTextData(const String& text, const HFont& font, UINT32 fontSize, UINT32 width, UINT32 height, bool wordWrap)
+	std::shared_ptr<TextUtility::TextData> TextUtility::getTextData(const WString& text, const HFont& font, UINT32 fontSize, UINT32 width, UINT32 height, bool wordWrap)
 	{
 		const FontData* fontData = nullptr;
 		if(font != nullptr)

+ 2 - 0
CamelotOISInput/Include/CmInputHandlerOIS.h

@@ -16,10 +16,12 @@ namespace CamelotFramework
 		InputHandlerOIS(unsigned int hWnd);
 		virtual ~InputHandlerOIS();
 
+		const WString& getInputString() const { return mInputString; }
 	private:
 		OIS::InputManager*	mInputManager;
 		OIS::Mouse*			mMouse;
 		OIS::Keyboard*		mKeyboard;
+		WString				mInputString;
 
 		virtual bool keyPressed(const OIS::KeyEvent& arg);
 		virtual bool keyReleased(const OIS::KeyEvent& arg);

+ 3 - 1
CamelotOISInput/Source/CmInputHandlerOIS.cpp

@@ -58,10 +58,13 @@ namespace CamelotFramework
 	{
 		mMouse->capture();
 		mKeyboard->capture();
+
+		mInputString = "";
 	}
 
 	bool InputHandlerOIS::keyPressed(const OIS::KeyEvent &arg)
 	{
+		mInputString += arg.text;
 		onKeyDown((KeyCode)(int)arg.key);
 
 		return true;
@@ -70,7 +73,6 @@ namespace CamelotFramework
 	bool InputHandlerOIS::keyReleased(const OIS::KeyEvent& arg)
 	{
 		onKeyUp((KeyCode)(int)arg.key);
-
 		return true;
 	}
 

+ 1 - 0
CamelotUtility/Include/CmString.h

@@ -79,6 +79,7 @@ namespace CamelotFramework {
 		typedef _StringBase String;
 		typedef _StringStreamBase StringStream;
 		typedef StringStream stringstream;
+		typedef String WString; // TODO - A temporary value I'll use for things that will need Unicode. I don't use Unicode yet though
 
 	/** \addtogroup Core
 	*  @{

+ 12 - 0
TODO.txt

@@ -59,11 +59,23 @@ EditorWindowContainer
  - Contents
    - Actual Editor Window with custom contents
 
+MemoryAllocator - std::string still uses default allocator
+ ALSO possibly rename my custom vector/list/etc classes to Vector/List, etc. So its all standardized
 
 GUIDragManager
  - GUI system sends startdrag/enddrag/drag events to all elements
  - startDrag(void* userPtr) changes cursor
  - releasing the cursor sends enddrag event and then the control can retrieve the user ptr
+ - SINCE currently non-active elements ignore drag events, add GUIElement::acceptsMouseDrop property
+   - Such elements will receive mouse drag and mouse up events if other element is active, and they can filter if they want to accept it
+
+Keyboard input:
+ - Events like Tab, Backspace, Delete, Ctrl+V, Ctrl+C, Ctrl+A, Ctrl+D use a special CommandEvent
+ - How will my GUI system handle joysticks and touchscreens and such?
+  - Key-remapping is not relevant for GUI, only for game controls
+  - Add support for joystick and joystick keys - along with keyboard ones
+  - Then add support for shortcut keys for certain GUIElements
+ - I also need to block input for Components when focus is not on game window...
 
 -----------