Selaa lähdekoodia

Completely refactored input so text/mouse/axis handling is more intuitive

Marko Pintera 12 vuotta sitten
vanhempi
sitoutus
da1e117f66

+ 5 - 5
BansheeEngine/Include/BsGUIKeyEvent.h

@@ -1,7 +1,7 @@
 #pragma once
 #pragma once
 
 
 #include "BsPrerequisites.h"
 #include "BsPrerequisites.h"
-#include "CmInputHandler.h"
+#include "CmInputFwd.h"
 #include "CmInt2.h"
 #include "CmInt2.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
@@ -19,17 +19,17 @@ namespace BansheeEngine
 		GUIKeyEvent();
 		GUIKeyEvent();
 
 
 		GUIKeyEventType getType() const { return mType; }
 		GUIKeyEventType getType() const { return mType; }
-		CM::KeyCode getKey() const { return mKey; }
+		CM::ButtonCode getKey() const { return mKey; }
 		const CM::UINT32& getInputChar() const { return mInputChar; }
 		const CM::UINT32& getInputChar() const { return mInputChar; }
 	private:
 	private:
 		friend class GUIManager;
 		friend class GUIManager;
 
 
 		GUIKeyEventType mType;
 		GUIKeyEventType mType;
-		CM::KeyCode mKey;
+		CM::ButtonCode mKey;
 		CM::UINT32 mInputChar;
 		CM::UINT32 mInputChar;
 
 
-		void setKeyDownData(CM::KeyCode key);
-		void setKeyUpData(CM::KeyCode key);
+		void setKeyDownData(CM::ButtonCode key);
+		void setKeyUpData(CM::ButtonCode key);
 		void setTextInputData(CM::UINT32 inputChar);
 		void setTextInputData(CM::UINT32 inputChar);
 	};
 	};
 }
 }

+ 10 - 11
BansheeEngine/Include/BsGUIManager.h

@@ -4,7 +4,7 @@
 #include "BsGUIMouseEvent.h"
 #include "BsGUIMouseEvent.h"
 #include "BsGUIKeyEvent.h"
 #include "BsGUIKeyEvent.h"
 #include "CmModule.h"
 #include "CmModule.h"
-#include "CmInputHandler.h"
+#include "CmInput.h"
 #include "CmDeferredRenderContextFwd.h"
 #include "CmDeferredRenderContextFwd.h"
 #include <boost/signals/connection.hpp>
 #include <boost/signals/connection.hpp>
 
 
@@ -48,7 +48,7 @@ namespace BansheeEngine
 		// Element and widget that's being clicked on
 		// Element and widget that's being clicked on
 		GUIWidget* mActiveWidget;
 		GUIWidget* mActiveWidget;
 		GUIElement* mActiveElement;
 		GUIElement* mActiveElement;
-		CM::UINT32 mActiveMouseButton;
+		GUIMouseButton mActiveMouseButton;
 
 
 		// Element and widget that currently have the keyboard focus
 		// Element and widget that currently have the keyboard focus
 		GUIWidget* mKeyboardFocusWidget;
 		GUIWidget* mKeyboardFocusWidget;
@@ -60,11 +60,10 @@ namespace BansheeEngine
 		GUIMouseEvent mMouseEvent;
 		GUIMouseEvent mMouseEvent;
 		GUIKeyEvent mKeyEvent;
 		GUIKeyEvent mKeyEvent;
 
 
+		boost::signals::connection mOnButtonDownConn;
+		boost::signals::connection mOnButtonUpConn;
 		boost::signals::connection mOnMouseMovedConn;
 		boost::signals::connection mOnMouseMovedConn;
-		boost::signals::connection mOnMouseDownConn;
-		boost::signals::connection mOnMouseUpConn;
-		boost::signals::connection mOnKeyDownConn;
-		boost::signals::connection mOnKeyUpConn;
+		boost::signals::connection mOnTextInputConn;
 
 
 		boost::signals::connection mWindowGainedFocusConn;
 		boost::signals::connection mWindowGainedFocusConn;
 		boost::signals::connection mWindowLostFocusConn;
 		boost::signals::connection mWindowLostFocusConn;
@@ -72,17 +71,17 @@ namespace BansheeEngine
 
 
 		void updateMeshes();
 		void updateMeshes();
 
 
-		void onKeyDown(const CM::KeyEvent& event);
-		void onKeyUp(const CM::KeyEvent& event);
+		void onButtonDown(const CM::ButtonEvent& event);
+		void onButtonUp(const CM::ButtonEvent& event);
 
 
 		void onMouseMoved(const CM::MouseEvent& event);
 		void onMouseMoved(const CM::MouseEvent& event);
-		void onMouseDown(const CM::MouseEvent& event, CM::MouseButton buttonID);
-		void onMouseUp(const CM::MouseEvent& event, CM::MouseButton buttonID);
+		void onTextInput(const CM::TextInputEvent& event);
 
 
 		void onWindowFocusGained(CM::RenderWindow& win);
 		void onWindowFocusGained(CM::RenderWindow& win);
 		void onWindowFocusLost(CM::RenderWindow& win);
 		void onWindowFocusLost(CM::RenderWindow& win);
 		void onWindowMovedOrResized(CM::RenderWindow& win);
 		void onWindowMovedOrResized(CM::RenderWindow& win);
 
 
-		CM::Int2 getWidgetRelativePos(const GUIWidget& widget, const CM::Int2& screenPos);
+		GUIMouseButton buttonToMouseButton(CM::ButtonCode code) const;
+		CM::Int2 getWidgetRelativePos(const GUIWidget& widget, const CM::Int2& screenPos) const;
 	};
 	};
 }
 }

+ 12 - 8
BansheeEngine/Include/BsGUIMouseEvent.h

@@ -1,7 +1,6 @@
 #pragma once
 #pragma once
 
 
 #include "BsPrerequisites.h"
 #include "BsPrerequisites.h"
-#include "CmInputHandler.h"
 #include "CmInt2.h"
 #include "CmInt2.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
@@ -18,33 +17,38 @@ namespace BansheeEngine
 		MouseDragEnd
 		MouseDragEnd
 	};
 	};
 
 
+	enum class GUIMouseButton
+	{
+		Left, Right, Middle, Count
+	};
+
 	class BS_EXPORT GUIMouseEvent
 	class BS_EXPORT GUIMouseEvent
 	{
 	{
 	public:
 	public:
 		GUIMouseEvent();
 		GUIMouseEvent();
-		GUIMouseEvent(bool buttonStates[CM::MB_Count]);
+		GUIMouseEvent(bool buttonStates[GUIMouseButton::Count]);
 
 
 		const CM::Int2& getPosition() const { return mPosition; }
 		const CM::Int2& getPosition() const { return mPosition; }
 		GUIMouseEventType getType() const { return mType; }
 		GUIMouseEventType getType() const { return mType; }
-		CM::MouseButton getButton() const { return mButton; }
+		GUIMouseButton getButton() const { return mButton; }
 		CM::Int2 getDragAmount() const { return mDragAmount; }
 		CM::Int2 getDragAmount() const { return mDragAmount; }
-		bool isButtonDown(CM::MouseButton button) const { return mButtonStates[(int)button]; }
+		bool isButtonDown(GUIMouseButton button) const { return mButtonStates[(int)button]; }
 		GUIElement* getMouseOverElement() const { return mMouseOverElement; }
 		GUIElement* getMouseOverElement() const { return mMouseOverElement; }
 	private:
 	private:
 		friend class GUIManager;
 		friend class GUIManager;
 
 
+		bool mButtonStates[GUIMouseButton::Count];
 		CM::Int2 mPosition;
 		CM::Int2 mPosition;
 		CM::Int2 mDragAmount;
 		CM::Int2 mDragAmount;
 		GUIMouseEventType mType;
 		GUIMouseEventType mType;
-		CM::MouseButton mButton;
-		bool mButtonStates[CM::MB_Count];
+		GUIMouseButton mButton;
 		GUIElement* mMouseOverElement;
 		GUIElement* mMouseOverElement;
 
 
 		void setMouseOverData(GUIElement* mouseOverElement, const CM::Int2& position);
 		void setMouseOverData(GUIElement* mouseOverElement, const CM::Int2& position);
 		void setMouseOutData(GUIElement* mouseOverElement, const CM::Int2& position);
 		void setMouseOutData(GUIElement* mouseOverElement, const CM::Int2& position);
 		void setMouseMoveData(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 setMouseUpData(GUIElement* mouseOverElement, const CM::Int2& position, GUIMouseButton button);
+		void setMouseDownData(GUIElement* mouseOverElement, const CM::Int2& position, GUIMouseButton button);
 
 
 		void setMouseDragData(GUIElement* mouseOverElement, const CM::Int2& position, const CM::Int2& dragAmount);
 		void setMouseDragData(GUIElement* mouseOverElement, const CM::Int2& position, const CM::Int2& dragAmount);
 		void setMouseDragStartData(GUIElement* mouseOverElement, const CM::Int2& position);
 		void setMouseDragStartData(GUIElement* mouseOverElement, const CM::Int2& position);

+ 1 - 1
BansheeEngine/Source/BsGUIInputBox.cpp

@@ -235,7 +235,7 @@ namespace BansheeEngine
 	{
 	{
 		if(ev.getType() == GUIKeyEventType::KeyDown)
 		if(ev.getType() == GUIKeyEventType::KeyDown)
 		{
 		{
-			if(ev.getKey() == KC_BACK)
+			if(ev.getKey() == BC_BACK)
 			{
 			{
 				if(mText.size() > 0)
 				if(mText.size() > 0)
 				{
 				{

+ 4 - 4
BansheeEngine/Source/BsGUIKeyEvent.cpp

@@ -5,19 +5,19 @@ using namespace CamelotFramework;
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	GUIKeyEvent::GUIKeyEvent()
 	GUIKeyEvent::GUIKeyEvent()
-		:mType(GUIKeyEventType::KeyDown), mKey(KC_0)
+		:mType(GUIKeyEventType::KeyDown), mKey(BC_0)
 	{
 	{
 
 
 	}
 	}
 
 
-	void GUIKeyEvent::setKeyDownData(KeyCode key)
+	void GUIKeyEvent::setKeyDownData(ButtonCode key)
 	{
 	{
 		mType = GUIKeyEventType::KeyDown;
 		mType = GUIKeyEventType::KeyDown;
 		mKey = key;
 		mKey = key;
 		mInputChar = 0;
 		mInputChar = 0;
 	}
 	}
 
 
-	void GUIKeyEvent::setKeyUpData(KeyCode key)
+	void GUIKeyEvent::setKeyUpData(ButtonCode key)
 	{
 	{
 		mType = GUIKeyEventType::KeyUp;
 		mType = GUIKeyEventType::KeyUp;
 		mKey = key;
 		mKey = key;
@@ -27,7 +27,7 @@ namespace BansheeEngine
 	void GUIKeyEvent::setTextInputData(UINT32 inputChar)
 	void GUIKeyEvent::setTextInputData(UINT32 inputChar)
 	{
 	{
 		mType = GUIKeyEventType::TextInput;
 		mType = GUIKeyEventType::TextInput;
-		mKey = KC_0;
+		mKey = BC_0;
 		mInputChar = inputChar;
 		mInputChar = inputChar;
 	}
 	}
 }
 }

+ 119 - 104
BansheeEngine/Source/BsGUIManager.cpp

@@ -42,13 +42,12 @@ namespace BansheeEngine
 
 
 	GUIManager::GUIManager()
 	GUIManager::GUIManager()
 		:mMouseOverElement(nullptr), mMouseOverWidget(nullptr), mSeparateMeshesByWidget(true), mActiveElement(nullptr), 
 		:mMouseOverElement(nullptr), mMouseOverWidget(nullptr), mSeparateMeshesByWidget(true), mActiveElement(nullptr), 
-		mActiveWidget(nullptr), mActiveMouseButton(0), mKeyboardFocusElement(nullptr), mKeyboardFocusWidget(nullptr)
+		mActiveWidget(nullptr), mActiveMouseButton(GUIMouseButton::Left), mKeyboardFocusElement(nullptr), mKeyboardFocusWidget(nullptr)
 	{
 	{
-		mOnKeyDownConn = gInput().onKeyDown.connect(boost::bind(&GUIManager::onKeyDown, this, _1));
-		mOnKeyUpConn = gInput().onKeyUp.connect(boost::bind(&GUIManager::onKeyUp, this, _1));
+		mOnButtonDownConn = gInput().onKeyDown.connect(boost::bind(&GUIManager::onButtonDown, this, _1));
+		mOnButtonUpConn = gInput().onKeyUp.connect(boost::bind(&GUIManager::onButtonUp, this, _1));
 		mOnMouseMovedConn = gInput().onMouseMoved.connect(boost::bind(&GUIManager::onMouseMoved, this, _1));
 		mOnMouseMovedConn = gInput().onMouseMoved.connect(boost::bind(&GUIManager::onMouseMoved, this, _1));
-		mOnMouseDownConn = gInput().onMouseDown.connect(boost::bind(&GUIManager::onMouseDown, this, _1, _2));
-		mOnMouseUpConn = gInput().onMouseUp.connect(boost::bind(&GUIManager::onMouseUp, this, _1, _2));
+		mOnTextInputConn = gInput().onCharInput.connect(boost::bind(&GUIManager::onTextInput, this, _1)); 
 
 
 		mWindowGainedFocusConn = RenderWindowManager::instance().onFocusGained.connect(boost::bind(&GUIManager::onWindowFocusGained, this, _1));
 		mWindowGainedFocusConn = RenderWindowManager::instance().onFocusGained.connect(boost::bind(&GUIManager::onWindowFocusGained, this, _1));
 		mWindowLostFocusConn = RenderWindowManager::instance().onFocusLost.connect(boost::bind(&GUIManager::onWindowFocusLost, this, _1));
 		mWindowLostFocusConn = RenderWindowManager::instance().onFocusLost.connect(boost::bind(&GUIManager::onWindowFocusLost, this, _1));
@@ -57,11 +56,10 @@ namespace BansheeEngine
 
 
 	GUIManager::~GUIManager()
 	GUIManager::~GUIManager()
 	{
 	{
-		mOnKeyDownConn.disconnect();
-		mOnKeyUpConn.disconnect();
+		mOnButtonDownConn.disconnect();
+		mOnButtonUpConn.disconnect();
 		mOnMouseMovedConn.disconnect();
 		mOnMouseMovedConn.disconnect();
-		mOnMouseDownConn.disconnect();
-		mOnMouseUpConn.disconnect();
+		mOnTextInputConn.disconnect();
 
 
 		mWindowGainedFocusConn.disconnect();
 		mWindowGainedFocusConn.disconnect();
 		mWindowLostFocusConn.disconnect();
 		mWindowLostFocusConn.disconnect();
@@ -412,34 +410,111 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	void GUIManager::onKeyDown(const KeyEvent& event)
+	void GUIManager::onButtonDown(const ButtonEvent& event)
 	{
 	{
 		if(event.isUsed())
 		if(event.isUsed())
 			return;
 			return;
 
 
-		if(mKeyboardFocusElement != nullptr)
+		if(event.isKeyboard())
 		{
 		{
-			mKeyEvent = GUIKeyEvent();
+			if(mKeyboardFocusElement != nullptr)
+			{
+				mKeyEvent = GUIKeyEvent();
+
+				mKeyEvent.setKeyDownData(event.buttonCode);
+				mKeyboardFocusWidget->_keyEvent(mKeyboardFocusElement, mKeyEvent);
+			}
+		}
+
+		if(event.isMouse())
+		{
+			// TODO - Maybe avoid querying these for every event separately?
+			bool buttonStates[(int)GUIMouseButton::Count];
+			buttonStates[0] = gInput().isButtonDown(BC_MOUSE_LEFT);
+			buttonStates[1] = gInput().isButtonDown(BC_MOUSE_MIDDLE);
+			buttonStates[2] = gInput().isButtonDown(BC_MOUSE_RIGHT);
+
+			mMouseEvent = GUIMouseEvent(buttonStates);
 
 
-			mKeyEvent.setKeyDownData(event.keyCode);
-			bool keyDownHandled = mKeyboardFocusWidget->_keyEvent(mKeyboardFocusElement, mKeyEvent);
+			GUIMouseButton guiButton = buttonToMouseButton(event.buttonCode);
 
 
-			// If key down wasn't handled, send text input event if pressed character is textual
-			if(!keyDownHandled && event.textChar != 0)
+			// 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 && mMouseOverElement != nullptr;
+			if(acceptMouseDown)
 			{
 			{
-				mKeyEvent.setTextInputData(event.textChar);
-				mKeyboardFocusWidget->_keyEvent(mKeyboardFocusElement, mKeyEvent);
+				Int2 localPos = getWidgetRelativePos(*mMouseOverWidget, gInput().getMousePosition());
+
+				mMouseEvent.setMouseDownData(mMouseOverElement, localPos, guiButton);
+				mMouseOverWidget->_mouseEvent(mMouseOverElement, 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(mMouseOverElement, localPos);
+				mMouseOverWidget->_mouseEvent(mMouseOverElement, mMouseEvent);
+
+				mActiveElement = mMouseOverElement;
+				mActiveWidget = mMouseOverWidget;
+				mActiveMouseButton = guiButton;
 			}
 			}
+
+			if(mKeyboardFocusElement != nullptr && mMouseOverElement != mKeyboardFocusElement)
+				mKeyboardFocusElement->_setFocus(false);
+
+			if(mMouseOverElement != nullptr)
+				mMouseOverElement->_setFocus(true);
+
+			mKeyboardFocusElement = mMouseOverElement;
+			mKeyboardFocusWidget = mMouseOverWidget;
 		}
 		}
 		
 		
 		event.markAsUsed();
 		event.markAsUsed();
 	}
 	}
 
 
-	void GUIManager::onKeyUp(const KeyEvent& event)
+	void GUIManager::onButtonUp(const ButtonEvent& event)
 	{
 	{
 		if(event.isUsed())
 		if(event.isUsed())
 			return;
 			return;
 
 
+		// TODO - Maybe avoid querying these for every event separately?
+		if(event.isMouse())
+		{
+			bool buttonStates[(int)GUIMouseButton::Count];
+			buttonStates[0] = gInput().isButtonDown(BC_MOUSE_LEFT);
+			buttonStates[1] = gInput().isButtonDown(BC_MOUSE_MIDDLE);
+			buttonStates[2] = gInput().isButtonDown(BC_MOUSE_RIGHT);
+
+			mMouseEvent = GUIMouseEvent(buttonStates);
+
+			Int2 localPos;
+			if(mMouseOverWidget != nullptr)
+			{
+				localPos = getWidgetRelativePos(*mMouseOverWidget, gInput().getMousePosition());
+			}
+
+			GUIMouseButton guiButton = buttonToMouseButton(event.buttonCode);
+
+			// Send MouseUp event only if we are over the active element (we don't want to accidentally trigger other elements).
+			// And only activate when a button that originally caused the active state is released, otherwise ignore it.
+			bool acceptMouseUp = mActiveMouseButton == guiButton && (mMouseOverElement != nullptr && mActiveElement == mMouseOverElement);
+			if(acceptMouseUp)
+			{
+				mMouseEvent.setMouseUpData(mMouseOverElement, localPos, guiButton);
+				mMouseOverWidget->_mouseEvent(mMouseOverElement, mMouseEvent);
+			}
+
+			// Send DragEnd event to whichever element is active
+			bool acceptEndDrag = mActiveMouseButton == guiButton && mActiveElement != nullptr;
+			if(acceptEndDrag)
+			{
+				mMouseEvent.setMouseDragEndData(mMouseOverElement, localPos);
+				mActiveWidget->_mouseEvent(mActiveElement, mMouseEvent);
+
+				mActiveElement = nullptr;
+				mActiveWidget = nullptr;
+				mActiveMouseButton = GUIMouseButton::Left;
+			}	
+		}
+
 		event.markAsUsed();
 		event.markAsUsed();
 	}
 	}
 
 
@@ -464,9 +539,10 @@ namespace BansheeEngine
 #endif
 #endif
 
 
 		// TODO - Maybe avoid querying these for every event separately?
 		// TODO - Maybe avoid querying these for every event separately?
-		bool buttonStates[(int)MB_Count];
-		for(int i = 0; i < MB_Count; i++)
-			buttonStates[i] = gInput().isButtonDown((MouseButton)i);
+		bool buttonStates[(int)GUIMouseButton::Count];
+		buttonStates[0] = gInput().isButtonDown(BC_MOUSE_LEFT);
+		buttonStates[1] = gInput().isButtonDown(BC_MOUSE_MIDDLE);
+		buttonStates[2] = gInput().isButtonDown(BC_MOUSE_RIGHT);
 
 
 		mMouseEvent = GUIMouseEvent(buttonStates);
 		mMouseEvent = GUIMouseEvent(buttonStates);
 
 
@@ -490,7 +566,7 @@ namespace BansheeEngine
 		{
 		{
 			const RenderWindow* window = widgetInFocus->getOwnerWindow();
 			const RenderWindow* window = widgetInFocus->getOwnerWindow();
 
 
-			Int2 screenPos = window->screenToWindowPos(event.coords);
+			Int2 screenPos = window->screenToWindowPos(event.screenPos);
 			Vector4 vecScreenPos((float)screenPos.x, (float)screenPos.y, 0.0f, 1.0f);
 			Vector4 vecScreenPos((float)screenPos.x, (float)screenPos.y, 0.0f, 1.0f);
 
 
 			UINT32 topMostDepth = std::numeric_limits<UINT32>::max();
 			UINT32 topMostDepth = std::numeric_limits<UINT32>::max();
@@ -536,7 +612,7 @@ namespace BansheeEngine
 				// Send MouseOut event
 				// Send MouseOut event
 				if(mActiveElement == nullptr || mMouseOverElement == mActiveElement)
 				if(mActiveElement == nullptr || mMouseOverElement == mActiveElement)
 				{
 				{
-					Int2 curLocalPos = getWidgetRelativePos(*mMouseOverWidget, event.coords);
+					Int2 curLocalPos = getWidgetRelativePos(*mMouseOverWidget, event.screenPos);
 
 
 					mMouseEvent.setMouseOutData(topMostElement, curLocalPos);
 					mMouseEvent.setMouseOutData(topMostElement, curLocalPos);
 					mMouseOverWidget->_mouseEvent(mMouseOverElement, mMouseEvent);
 					mMouseOverWidget->_mouseEvent(mMouseOverElement, mMouseEvent);
@@ -557,7 +633,7 @@ namespace BansheeEngine
 		// If mouse is being held down send MouseDrag events
 		// If mouse is being held down send MouseDrag events
 		if(mActiveElement != nullptr)
 		if(mActiveElement != nullptr)
 		{
 		{
-			Int2 curLocalPos = getWidgetRelativePos(*mActiveWidget, event.coords);
+			Int2 curLocalPos = getWidgetRelativePos(*mActiveWidget, event.screenPos);
 
 
 			if(mLastCursorLocalPos != curLocalPos)
 			if(mLastCursorLocalPos != curLocalPos)
 			{
 			{
@@ -588,89 +664,16 @@ namespace BansheeEngine
 		event.markAsUsed();
 		event.markAsUsed();
 	}
 	}
 
 
-	void GUIManager::onMouseDown(const MouseEvent& event, MouseButton buttonID)
+	void GUIManager::onTextInput(const CM::TextInputEvent& event)
 	{
 	{
-		if(event.isUsed())
-			return;
-
-		// TODO - Maybe avoid querying these for every event separately?
-		bool buttonStates[(int)MB_Count];
-		for(int i = 0; i < MB_Count; i++)
-			buttonStates[i] = gInput().isButtonDown((MouseButton)i);
-
-		mMouseEvent = GUIMouseEvent(buttonStates);
-
-		// 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 && mMouseOverElement != nullptr;
-		if(acceptMouseDown)
+		if(mKeyboardFocusElement != nullptr)
 		{
 		{
-			Int2 localPos = getWidgetRelativePos(*mMouseOverWidget, event.coords);
-
-			mMouseEvent.setMouseDownData(mMouseOverElement, localPos, buttonID);
-			mMouseOverWidget->_mouseEvent(mMouseOverElement, 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(mMouseOverElement, localPos);
-			mMouseOverWidget->_mouseEvent(mMouseOverElement, mMouseEvent);
-
-			mActiveElement = mMouseOverElement;
-			mActiveWidget = mMouseOverWidget;
-			mActiveMouseButton = (UINT32)buttonID;
-		}
-
-		if(mKeyboardFocusElement != nullptr && mMouseOverElement != mKeyboardFocusElement)
-			mKeyboardFocusElement->_setFocus(false);
-
-		if(mMouseOverElement != nullptr)
-			mMouseOverElement->_setFocus(true);
-
-		mKeyboardFocusElement = mMouseOverElement;
-		mKeyboardFocusWidget = mMouseOverWidget;
-
-		event.markAsUsed();
-	}
-
-	void GUIManager::onMouseUp(const MouseEvent& event, MouseButton buttonID)
-	{
-		if(event.isUsed())
-			return;
-
-		// TODO - Maybe avoid querying these for every event separately?
-		bool buttonStates[(int)MB_Count];
-		for(int i = 0; i < MB_Count; i++)
-			buttonStates[i] = gInput().isButtonDown((MouseButton)i);
-
-		mMouseEvent = GUIMouseEvent(buttonStates);
+			mKeyEvent = GUIKeyEvent();
 
 
-		Int2 localPos;
-		if(mMouseOverWidget != nullptr)
-		{
-			localPos = getWidgetRelativePos(*mMouseOverWidget, event.coords);
-		}
+			mKeyEvent.setTextInputData(event.textChar);
+			mKeyboardFocusWidget->_keyEvent(mKeyboardFocusElement, mKeyEvent);
 
 
-		// Send MouseUp event only if we are over the active element (we don't want to accidentally trigger other elements).
-		// And only activate when a button that originally caused the active state is released, otherwise ignore it.
-		bool acceptMouseUp = mActiveMouseButton == (UINT32)buttonID && (mMouseOverElement != nullptr && mActiveElement == mMouseOverElement);
-		if(acceptMouseUp)
-		{
-			mMouseEvent.setMouseUpData(mMouseOverElement, localPos, buttonID);
-			mMouseOverWidget->_mouseEvent(mMouseOverElement, mMouseEvent);
 		}
 		}
-
-		// Send DragEnd event to whichever element is active
-		bool acceptEndDrag = mActiveMouseButton == (UINT32)buttonID && mActiveElement != nullptr;
-		if(acceptEndDrag)
-		{
-			mMouseEvent.setMouseDragEndData(mMouseOverElement, localPos);
-			mActiveWidget->_mouseEvent(mActiveElement, mMouseEvent);
-
-			mActiveElement = nullptr;
-			mActiveWidget = nullptr;
-			mActiveMouseButton = 0;
-		}	
-
-		event.markAsUsed();
 	}
 	}
 
 
 	void GUIManager::onWindowFocusGained(RenderWindow& win)
 	void GUIManager::onWindowFocusGained(RenderWindow& win)
@@ -700,7 +703,19 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	Int2 GUIManager::getWidgetRelativePos(const GUIWidget& widget, const Int2& screenPos)
+	GUIMouseButton GUIManager::buttonToMouseButton(ButtonCode code) const
+	{
+		if(code == BC_MOUSE_LEFT)
+			return GUIMouseButton::Left;
+		else if(code == BC_MOUSE_MIDDLE)
+			return GUIMouseButton::Middle;
+		else if(code == BC_MOUSE_RIGHT)
+			return GUIMouseButton::Right;
+
+		CM_EXCEPT(InvalidParametersException, "Provided button code is not a GUI supported mouse button.");
+	}
+
+	Int2 GUIManager::getWidgetRelativePos(const GUIWidget& widget, const Int2& screenPos) const
 	{
 	{
 		const RenderWindow* window = widget.getOwnerWindow();
 		const RenderWindow* window = widget.getOwnerWindow();
 		Int2 windowPos = window->screenToWindowPos(screenPos);
 		Int2 windowPos = window->screenToWindowPos(screenPos);

+ 12 - 12
BansheeEngine/Source/BsGUIMouseEvent.cpp

@@ -5,13 +5,13 @@ using namespace CamelotFramework;
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	GUIMouseEvent::GUIMouseEvent()
 	GUIMouseEvent::GUIMouseEvent()
-		:mType(GUIMouseEventType::MouseMove), mButton(MB_Left), mMouseOverElement(nullptr)
+		:mType(GUIMouseEventType::MouseMove), mButton(GUIMouseButton::Left), mMouseOverElement(nullptr)
 	{
 	{
-		memset(mButtonStates, 0, sizeof(mButtonStates));
+
 	}
 	}
 
 
-	GUIMouseEvent::GUIMouseEvent(bool buttonStates[MB_Count])
-		:mType(GUIMouseEventType::MouseMove), mButton(MB_Left), mMouseOverElement(nullptr)
+	GUIMouseEvent::GUIMouseEvent(bool buttonStates[GUIMouseButton::Count])
+		:mType(GUIMouseEventType::MouseMove), mButton(GUIMouseButton::Left), mMouseOverElement(nullptr)
 	{
 	{
 		memcpy(mButtonStates, buttonStates, sizeof(mButtonStates));
 		memcpy(mButtonStates, buttonStates, sizeof(mButtonStates));
 	}
 	}
@@ -21,7 +21,7 @@ namespace BansheeEngine
 		mType = GUIMouseEventType::MouseOver;
 		mType = GUIMouseEventType::MouseOver;
 		mPosition = position;
 		mPosition = position;
 		mMouseOverElement = mouseOverElement;
 		mMouseOverElement = mouseOverElement;
-		mButton = MB_Left;
+		mButton = GUIMouseButton::Left;
 		mDragAmount = Int2();
 		mDragAmount = Int2();
 	}
 	}
 
 
@@ -30,7 +30,7 @@ namespace BansheeEngine
 		mType = GUIMouseEventType::MouseOut;
 		mType = GUIMouseEventType::MouseOut;
 		mPosition = position;
 		mPosition = position;
 		mMouseOverElement = mouseOverElement;
 		mMouseOverElement = mouseOverElement;
-		mButton = MB_Left;
+		mButton = GUIMouseButton::Left;
 		mDragAmount = Int2();
 		mDragAmount = Int2();
 	}
 	}
 
 
@@ -39,11 +39,11 @@ namespace BansheeEngine
 		mType = GUIMouseEventType::MouseMove;
 		mType = GUIMouseEventType::MouseMove;
 		mPosition = position;
 		mPosition = position;
 		mMouseOverElement = mouseOverElement;
 		mMouseOverElement = mouseOverElement;
-		mButton = MB_Left;
+		mButton = GUIMouseButton::Left;
 		mDragAmount = Int2();
 		mDragAmount = Int2();
 	}
 	}
 
 
-	void GUIMouseEvent::setMouseUpData(GUIElement* mouseOverElement, const Int2& position, MouseButton button)
+	void GUIMouseEvent::setMouseUpData(GUIElement* mouseOverElement, const Int2& position, GUIMouseButton button)
 	{
 	{
 		mType = GUIMouseEventType::MouseUp;
 		mType = GUIMouseEventType::MouseUp;
 		mPosition = position;
 		mPosition = position;
@@ -52,7 +52,7 @@ namespace BansheeEngine
 		mDragAmount = Int2();
 		mDragAmount = Int2();
 	}
 	}
 
 
-	void GUIMouseEvent::setMouseDownData(GUIElement* mouseOverElement, const Int2& position, MouseButton button)
+	void GUIMouseEvent::setMouseDownData(GUIElement* mouseOverElement, const Int2& position, GUIMouseButton button)
 	{
 	{
 		mType = GUIMouseEventType::MouseDown;
 		mType = GUIMouseEventType::MouseDown;
 		mPosition = position;
 		mPosition = position;
@@ -66,7 +66,7 @@ namespace BansheeEngine
 		mType = GUIMouseEventType::MouseDrag;
 		mType = GUIMouseEventType::MouseDrag;
 		mPosition = position;
 		mPosition = position;
 		mMouseOverElement = mouseOverElement;
 		mMouseOverElement = mouseOverElement;
-		mButton = MB_Left;
+		mButton = GUIMouseButton::Left;
 		mDragAmount = dragAmount;
 		mDragAmount = dragAmount;
 	}
 	}
 
 
@@ -75,7 +75,7 @@ namespace BansheeEngine
 		mType = GUIMouseEventType::MouseDragStart;
 		mType = GUIMouseEventType::MouseDragStart;
 		mPosition = position;
 		mPosition = position;
 		mMouseOverElement = mouseOverElement;
 		mMouseOverElement = mouseOverElement;
-		mButton = MB_Left;
+		mButton = GUIMouseButton::Left;
 		mDragAmount = Int2();
 		mDragAmount = Int2();
 	}
 	}
 
 
@@ -84,7 +84,7 @@ namespace BansheeEngine
 		mType = GUIMouseEventType::MouseDragEnd;
 		mType = GUIMouseEventType::MouseDragEnd;
 		mPosition = position;
 		mPosition = position;
 		mMouseOverElement = mouseOverElement;
 		mMouseOverElement = mouseOverElement;
-		mButton = MB_Left;
+		mButton = GUIMouseButton::Left;
 		mDragAmount = Int2();
 		mDragAmount = Int2();
 	}
 	}
 }
 }

+ 6 - 6
CamelotClient/CmDebugCamera.cpp

@@ -32,12 +32,12 @@ namespace CamelotFramework
 
 
 	void DebugCamera::update()
 	void DebugCamera::update()
 	{
 	{
-		bool goingForward = gInput().isKeyDown(KC_W) || gInput().isKeyDown(KC_UP);
-		bool goingBack = gInput().isKeyDown(KC_S) || gInput().isKeyDown(KC_DOWN);
-		bool goingLeft = gInput().isKeyDown(KC_A) || gInput().isKeyDown(KC_LEFT);
-		bool goingRight = gInput().isKeyDown(KC_D) || gInput().isKeyDown(KC_RIGHT);
-		bool fastMove = gInput().isKeyDown(KC_LSHIFT);
-		bool camRotating = gInput().isButtonDown(MB_Right);
+		bool goingForward = gInput().isButtonDown(BC_W) || gInput().isButtonDown(BC_UP);
+		bool goingBack = gInput().isButtonDown(BC_S) || gInput().isButtonDown(BC_DOWN);
+		bool goingLeft = gInput().isButtonDown(BC_A) || gInput().isButtonDown(BC_LEFT);
+		bool goingRight = gInput().isButtonDown(BC_D) || gInput().isButtonDown(BC_RIGHT);
+		bool fastMove = gInput().isButtonDown(BC_LSHIFT);
+		bool camRotating = gInput().isButtonDown(BC_MOUSE_RIGHT);
 
 
 		if(camRotating != mLastButtonState)
 		if(camRotating != mLastButtonState)
 		{
 		{

+ 0 - 1
CamelotClient/CmDebugCamera.h

@@ -2,7 +2,6 @@
 
 
 #include "BsPrerequisites.h"
 #include "BsPrerequisites.h"
 #include "CmComponent.h"
 #include "CmComponent.h"
-#include "CmInputHandler.h"
 #include "CmMath.h"
 #include "CmMath.h"
 
 
 namespace CamelotFramework
 namespace CamelotFramework

+ 4 - 1
CamelotCore/CamelotCore.vcxproj

@@ -185,6 +185,8 @@
     <ClInclude Include="Include\CmGpuResource.h" />
     <ClInclude Include="Include\CmGpuResource.h" />
     <ClInclude Include="Include\CmGpuResourceDataRTTI.h" />
     <ClInclude Include="Include\CmGpuResourceDataRTTI.h" />
     <ClInclude Include="Include\CmGpuResourceRTTI.h" />
     <ClInclude Include="Include\CmGpuResourceRTTI.h" />
+    <ClInclude Include="Include\CmInputFwd.h" />
+    <ClInclude Include="Include\CmOSInputHandler.h" />
     <ClInclude Include="Include\CmPixelData.h" />
     <ClInclude Include="Include\CmPixelData.h" />
     <ClInclude Include="Include\CmPixelDataRTTI.h" />
     <ClInclude Include="Include\CmPixelDataRTTI.h" />
     <ClInclude Include="Include\CmPixelUtil.h" />
     <ClInclude Include="Include\CmPixelUtil.h" />
@@ -239,7 +241,7 @@
     <ClInclude Include="Include\CmHighLevelGpuProgramManager.h" />
     <ClInclude Include="Include\CmHighLevelGpuProgramManager.h" />
     <ClInclude Include="Include\CmImporter.h" />
     <ClInclude Include="Include\CmImporter.h" />
     <ClInclude Include="Include\CmInput.h" />
     <ClInclude Include="Include\CmInput.h" />
-    <ClInclude Include="Include\CmInputHandler.h" />
+    <ClInclude Include="Include\CmRawInputHandler.h" />
     <ClInclude Include="Include\CmMaterial.h" />
     <ClInclude Include="Include\CmMaterial.h" />
     <ClInclude Include="Include\CmMaterialRTTI.h" />
     <ClInclude Include="Include\CmMaterialRTTI.h" />
     <ClInclude Include="Include\CmMesh.h" />
     <ClInclude Include="Include\CmMesh.h" />
@@ -331,6 +333,7 @@
     <ClCompile Include="Source\CmIndexData.cpp" />
     <ClCompile Include="Source\CmIndexData.cpp" />
     <ClCompile Include="Source\CmMeshManager.cpp" />
     <ClCompile Include="Source\CmMeshManager.cpp" />
     <ClCompile Include="Source\CmOcclusionQuery.cpp" />
     <ClCompile Include="Source\CmOcclusionQuery.cpp" />
+    <ClCompile Include="Source\CmOSInputHandler.cpp" />
     <ClCompile Include="Source\CmPixelBuffer.cpp" />
     <ClCompile Include="Source\CmPixelBuffer.cpp" />
     <ClCompile Include="Source\CmGpuProgIncludeImporter.cpp" />
     <ClCompile Include="Source\CmGpuProgIncludeImporter.cpp" />
     <ClCompile Include="Source\CmPixelData.cpp" />
     <ClCompile Include="Source\CmPixelData.cpp" />

+ 12 - 3
CamelotCore/CamelotCore.vcxproj.filters

@@ -201,9 +201,6 @@
     <ClInclude Include="Include\CmInput.h">
     <ClInclude Include="Include\CmInput.h">
       <Filter>Header Files\Input</Filter>
       <Filter>Header Files\Input</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="Include\CmInputHandler.h">
-      <Filter>Header Files\Input</Filter>
-    </ClInclude>
     <ClInclude Include="Include\CmComponentRTTI.h">
     <ClInclude Include="Include\CmComponentRTTI.h">
       <Filter>Header Files\RTTI</Filter>
       <Filter>Header Files\RTTI</Filter>
     </ClInclude>
     </ClInclude>
@@ -444,6 +441,15 @@
     <ClInclude Include="Include\CmTextUtility.h">
     <ClInclude Include="Include\CmTextUtility.h">
       <Filter>Header Files\Text</Filter>
       <Filter>Header Files\Text</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\CmOSInputHandler.h">
+      <Filter>Header Files\Input</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmRawInputHandler.h">
+      <Filter>Header Files\Input</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmInputFwd.h">
+      <Filter>Header Files\Input</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CmApplication.cpp">
     <ClCompile Include="Source\CmApplication.cpp">
@@ -683,5 +689,8 @@
     <ClCompile Include="Source\CmTextUtility.cpp">
     <ClCompile Include="Source\CmTextUtility.cpp">
       <Filter>Source Files\Text</Filter>
       <Filter>Source Files\Text</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\CmOSInputHandler.cpp">
+      <Filter>Source Files\Input</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 29 - 17
CamelotCore/Include/CmInput.h

@@ -3,7 +3,9 @@
 #include "CmPrerequisites.h"
 #include "CmPrerequisites.h"
 #include "CmModule.h"
 #include "CmModule.h"
 #include "CmRect.h"
 #include "CmRect.h"
-#include "CmInputHandler.h"
+#include "CmOSInputHandler.h"
+#include "CmRawInputHandler.h"
+#include "CmInputFwd.h"
 
 
 namespace CamelotFramework
 namespace CamelotFramework
 {
 {
@@ -13,14 +15,13 @@ namespace CamelotFramework
 		Input();
 		Input();
 		~Input();
 		~Input();
 
 
-		boost::signal<void(const KeyEvent&)> onKeyDown;
-		boost::signal<void(const KeyEvent&)> onKeyUp;
+		boost::signal<void(const ButtonEvent&)> onKeyDown;
+		boost::signal<void(const ButtonEvent&)> onKeyUp;
+		boost::signal<void(const TextInputEvent&)> onCharInput;
 
 
 		boost::signal<void(const MouseEvent&)> onMouseMoved;
 		boost::signal<void(const MouseEvent&)> onMouseMoved;
-		boost::signal<void(const MouseEvent&, MouseButton)> onMouseDown;
-		boost::signal<void(const MouseEvent&, MouseButton)> onMouseUp;
 
 
-		void registerInputHandler(InputHandlerPtr inputHandler);
+		void registerRawInputHandler(std::shared_ptr<RawInputHandler> inputHandler);
 
 
 		/**
 		/**
 		 * @brief	Called every frame. Dispatches any callbacks resulting from input by the user. Should only be called by Application.
 		 * @brief	Called every frame. Dispatches any callbacks resulting from input by the user. Should only be called by Application.
@@ -52,11 +53,13 @@ namespace CamelotFramework
 		 */
 		 */
 		float getVerticalAxis() const;
 		float getVerticalAxis() const;
 
 
-		bool isButtonDown(MouseButton button) const;
-		bool isKeyDown(KeyCode keyCode) const;
+		bool isButtonDown(ButtonCode keyCode) const;
+
+		Int2 getMousePosition() const { return mMouseAbsPos; }
 
 
 	private:
 	private:
-		InputHandlerPtr mInputHandler;
+		std::shared_ptr<RawInputHandler> mRawInputHandler;
+		std::shared_ptr<OSInputHandler> mOSInputHandler;
 
 
 		float mSmoothHorizontalAxis;
 		float mSmoothHorizontalAxis;
 		float mSmoothVerticalAxis;
 		float mSmoothVerticalAxis;
@@ -67,19 +70,28 @@ namespace CamelotFramework
 		int	mCurrentBufferIdx;
 		int	mCurrentBufferIdx;
 
 
 		Int2 mMouseLastRel;
 		Int2 mMouseLastRel;
+		Int2 mMouseAbsPos;
+
+		RawAxisState mAxes[RawInputAxis::Count];
+		bool mKeyState[BC_Count];
 
 
-		bool mMouseButtonState[MB_Count];
-		bool mKeyState[KC_Count];
+		void buttonDown(ButtonCode code);
+		void buttonUp(ButtonCode code);
 
 
-		void keyDown(const KeyEvent& event);
-		void keyUp(const KeyEvent& event);
+		void charInput(UINT32 chr);
 
 
-		void mouseMoved(const MouseEvent& event);
-		void mouseDown(const MouseEvent& event, MouseButton buttonID);
-		void mouseUp(const MouseEvent& event, MouseButton buttonID);
+		/**
+		 * @brief	Raw mouse/joystick axis input.
+		 */
+		void axisMoved(const RawAxisState& state, RawInputAxis axis);
 
 
 		/**
 		/**
-		 * @brief	Updates the input values that need smoothing.
+		 * @brief	Mouse movement as OS reports it. Used for screen cursor position.
+		 */
+		void mouseMoved(const Int2& screenPos);
+		
+		/**
+		 * @brief	Updates the axis input values that need smoothing.
 		 */
 		 */
 		void updateSmoothInput();
 		void updateSmoothInput();
 
 

+ 282 - 0
CamelotCore/Include/CmInputFwd.h

@@ -0,0 +1,282 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+#include "CmInt2.h"
+
+namespace CamelotFramework
+{
+	// Contains all possible keys, including keyboard scan codes, mouse buttons and gamepad buttons
+	// Note: These KeyCodes are only keyboard scan codes. This means that exact scan code identifier might 
+	// not correspond to that exact character on users keyboard, depending on users input locale. 
+	// Only for US locale will these scan code names will match the actual keyboard input. Think of the US key
+	// code names as only a convenience for more easily identifying which location on the keyboard a scan code represents.
+	//
+	// When storing these sequentially make sure to only reference the low order 2 bytes. Two high order bytes are used for various flags.
+	enum ButtonCode
+	{
+		BC_UNASSIGNED  = 0x00,
+		BC_ESCAPE      = 0x01,
+		BC_1           = 0x02,
+		BC_2           = 0x03,
+		BC_3           = 0x04,
+		BC_4           = 0x05,
+		BC_5           = 0x06,
+		BC_6           = 0x07,
+		BC_7           = 0x08,
+		BC_8           = 0x09,
+		BC_9           = 0x0A,
+		BC_0           = 0x0B,
+		BC_MINUS       = 0x0C,    // - on main keyboard
+		BC_EQUALS      = 0x0D,
+		BC_BACK        = 0x0E,    // backspace
+		BC_TAB         = 0x0F,
+		BC_Q           = 0x10,
+		BC_W           = 0x11,
+		BC_E           = 0x12,
+		BC_R           = 0x13,
+		BC_T           = 0x14,
+		BC_Y           = 0x15,
+		BC_U           = 0x16,
+		BC_I           = 0x17,
+		BC_O           = 0x18,
+		BC_P           = 0x19,
+		BC_LBRACKET    = 0x1A,
+		BC_RBRACKET    = 0x1B,
+		BC_RETURN      = 0x1C,    // Enter on main keyboard
+		BC_LCONTROL    = 0x1D,
+		BC_A           = 0x1E,
+		BC_S           = 0x1F,
+		BC_D           = 0x20,
+		BC_F           = 0x21,
+		BC_G           = 0x22,
+		BC_H           = 0x23,
+		BC_J           = 0x24,
+		BC_K           = 0x25,
+		BC_L           = 0x26,
+		BC_SEMICOLON   = 0x27,
+		BC_APOSTROPHE  = 0x28,
+		BC_GRAVE       = 0x29,    // accent
+		BC_LSHIFT      = 0x2A,
+		BC_BACKSLASH   = 0x2B,
+		BC_Z           = 0x2C,
+		BC_X           = 0x2D,
+		BC_C           = 0x2E,
+		BC_V           = 0x2F,
+		BC_B           = 0x30,
+		BC_N           = 0x31,
+		BC_M           = 0x32,
+		BC_COMMA       = 0x33,
+		BC_PERIOD      = 0x34,    // . on main keyboard
+		BC_SLASH       = 0x35,    // / on main keyboard
+		BC_RSHIFT      = 0x36,
+		BC_MULTIPLY    = 0x37,    // * on numeric keypad
+		BC_LMENU       = 0x38,    // left Alt
+		BC_SPACE       = 0x39,
+		BC_CAPITAL     = 0x3A,
+		BC_F1          = 0x3B,
+		BC_F2          = 0x3C,
+		BC_F3          = 0x3D,
+		BC_F4          = 0x3E,
+		BC_F5          = 0x3F,
+		BC_F6          = 0x40,
+		BC_F7          = 0x41,
+		BC_F8          = 0x42,
+		BC_F9          = 0x43,
+		BC_F10         = 0x44,
+		BC_NUMLOCK     = 0x45,
+		BC_SCROLL      = 0x46,    // Scroll Lock
+		BC_NUMPAD7     = 0x47,
+		BC_NUMPAD8     = 0x48,
+		BC_NUMPAD9     = 0x49,
+		BC_SUBTRACT    = 0x4A,    // - on numeric keypad
+		BC_NUMPAD4     = 0x4B,
+		BC_NUMPAD5     = 0x4C,
+		BC_NUMPAD6     = 0x4D,
+		BC_ADD         = 0x4E,    // + on numeric keypad
+		BC_NUMPAD1     = 0x4F,
+		BC_NUMPAD2     = 0x50,
+		BC_NUMPAD3     = 0x51,
+		BC_NUMPAD0     = 0x52,
+		BC_DECIMAL     = 0x53,    // . on numeric keypad
+		BC_OEM_102     = 0x56,    // < > | on UK/Germany keyboards
+		BC_F11         = 0x57,
+		BC_F12         = 0x58,
+		BC_F13         = 0x64,    //                     (NEC PC98)
+		BC_F14         = 0x65,    //                     (NEC PC98)
+		BC_F15         = 0x66,    //                     (NEC PC98)
+		BC_KANA        = 0x70,    // (Japanese keyboard)
+		BC_ABNT_C1     = 0x73,    // / ? on Portugese (Brazilian) keyboards
+		BC_CONVERT     = 0x79,    // (Japanese keyboard)
+		BC_NOCONVERT   = 0x7B,    // (Japanese keyboard)
+		BC_YEN         = 0x7D,    // (Japanese keyboard)
+		BC_ABNT_C2     = 0x7E,    // Numpad . on Portugese (Brazilian) keyboards
+		BC_NUMPADEQUALS= 0x8D,    // = on numeric keypad (NEC PC98)
+		BC_PREVTRACK   = 0x90,    // Previous Track (BC_CIRCUMFLEX on Japanese keyboard)
+		BC_AT          = 0x91,    //                     (NEC PC98)
+		BC_COLON       = 0x92,    //                     (NEC PC98)
+		BC_UNDERLINE   = 0x93,    //                     (NEC PC98)
+		BC_KANJI       = 0x94,    // (Japanese keyboard)
+		BC_STOP        = 0x95,    //                     (NEC PC98)
+		BC_AX          = 0x96,    //                     (Japan AX)
+		BC_UNLABELED   = 0x97,    //                        (J3100)
+		BC_NEXTTRACK   = 0x99,    // Next Track
+		BC_NUMPADENTER = 0x9C,    // Enter on numeric keypad
+		BC_RCONTROL    = 0x9D,
+		BC_MUTE        = 0xA0,    // Mute
+		BC_CALCULATOR  = 0xA1,    // Calculator
+		BC_PLAYPAUSE   = 0xA2,    // Play / Pause
+		BC_MEDIASTOP   = 0xA4,    // Media Stop
+		BC_VOLUMEDOWN  = 0xAE,    // Volume -
+		BC_VOLUMEUP    = 0xB0,    // Volume +
+		BC_WEBHOME     = 0xB2,    // Web home
+		BC_NUMPADCOMMA = 0xB3,    // , on numeric keypad (NEC PC98)
+		BC_DIVIDE      = 0xB5,    // / on numeric keypad
+		BC_SYSRQ       = 0xB7,
+		BC_RMENU       = 0xB8,    // right Alt
+		BC_PAUSE       = 0xC5,    // Pause
+		BC_HOME        = 0xC7,    // Home on arrow keypad
+		BC_UP          = 0xC8,    // UpArrow on arrow keypad
+		BC_PGUP        = 0xC9,    // PgUp on arrow keypad
+		BC_LEFT        = 0xCB,    // LeftArrow on arrow keypad
+		BC_RIGHT       = 0xCD,    // RightArrow on arrow keypad
+		BC_END         = 0xCF,    // End on arrow keypad
+		BC_DOWN        = 0xD0,    // DownArrow on arrow keypad
+		BC_PGDOWN      = 0xD1,    // PgDn on arrow keypad
+		BC_INSERT      = 0xD2,    // Insert on arrow keypad
+		BC_DELETE      = 0xD3,    // Delete on arrow keypad
+		BC_LWIN        = 0xDB,    // Left Windows key
+		BC_RWIN        = 0xDC,    // Right Windows key
+		BC_APPS        = 0xDD,    // AppMenu key
+		BC_POWER       = 0xDE,    // System Power
+		BC_SLEEP       = 0xDF,    // System Sleep
+		BC_WAKE        = 0xE3,    // System Wake
+		BC_WEBSEARCH   = 0xE5,    // Web Search
+		BC_WEBFAVORITES= 0xE6,    // Web Favorites
+		BC_WEBREFRESH  = 0xE7,    // Web Refresh
+		BC_WEBSTOP     = 0xE8,    // Web Stop
+		BC_WEBFORWARD  = 0xE9,    // Web Forward
+		BC_WEBBACK     = 0xEA,    // Web Back
+		BC_MYCOMPUTER  = 0xEB,    // My Computer
+		BC_MAIL        = 0xEC,    // Mail
+		BC_MEDIASELECT = 0xED,     // Media Select
+		BC_MOUSE_LEFT = 0x800000EE, // Mouse buttons - Most important bit signifies this key is a mouse button
+		BC_MOUSE_RIGHT = 0x800000EF,
+		BC_MOUSE_MIDDLE = 0x800000F0,
+		BC_MOUSE_BTN4 = 0x800000F1,
+		BC_MOUSE_BTN5 = 0x800000F2,
+		BC_MOUSE_BTN6 = 0x800000F3,
+		BC_MOUSE_BTN7 = 0x800000F4,
+		BC_MOUSE_BTN8 = 0x800000F5,
+		BC_MOUSE_BTN9 = 0x800000F6,
+		BC_MOUSE_BTN10 = 0x800000F7,
+		BC_MOUSE_BTN11 = 0x800000F8,
+		BC_MOUSE_BTN12 = 0x800000F9,
+		BC_MOUSE_BTN13 = 0x800000FA,
+		BC_MOUSE_BTN14 = 0x800000FB,
+		BC_MOUSE_BTN15 = 0x800000FC,
+		BC_MOUSE_BTN16 = 0x800000FD,
+		BC_MOUSE_BTN17 = 0x800000FE,
+		BC_MOUSE_BTN18 = 0x800000FF,
+		BC_MOUSE_BTN19 = 0x80000101,
+		BC_MOUSE_BTN20 = 0x80000102,
+		BC_MOUSE_BTN21 = 0x80000103,
+		BC_MOUSE_BTN22 = 0x80000104,
+		BC_MOUSE_BTN23 = 0x80000105,
+		BC_MOUSE_BTN24 = 0x80000106,
+		BC_MOUSE_BTN25 = 0x80000107,
+		BC_MOUSE_BTN26 = 0x80000108,
+		BC_MOUSE_BTN27 = 0x80000109,
+		BC_MOUSE_BTN28 = 0x8000010A,
+		BC_MOUSE_BTN29 = 0x8000010B,
+		BC_MOUSE_BTN30 = 0x8000010C,
+		BC_MOUSE_BTN31 = 0x8000010D,
+		BC_MOUSE_BTN32 = 0x8000010E,
+		BC_JOY_BTN1 = 0x4000010F, // Joystick/Gamepad buttons- Second most important bit signifies key is a joystick button
+		BC_JOY_BTN2 = 0x40000110,
+		BC_JOY_BTN3 = 0x40000111,
+		BC_JOY_BTN4 = 0x40000112,
+		BC_JOY_BTN5 = 0x40000113,
+		BC_JOY_BTN6 = 0x40000114,
+		BC_JOY_BTN7 = 0x40000115,
+		BC_JOY_BTN8 = 0x40000116,
+		BC_JOY_BTN9 = 0x40000117,
+		BC_JOY_BTN10 = 0x40000118,
+		BC_JOY_BTN11 = 0x40000119,
+		BC_JOY_BTN12 = 0x4000011A,
+		BC_JOY_BTN13 = 0x4000011B,
+		BC_JOY_BTN14 = 0x4000011C,
+		BC_JOY_BTN15 = 0x4000011D,
+		BC_JOY_BTN16 = 0x4000011E,
+		BC_JOY_BTN17 = 0x4000011F,
+		BC_JOY_BTN18 = 0x40000120,
+		BC_JOY_BTN19 = 0x40000121,
+		BC_JOY_BTN20 = 0x40000123,
+		BC_JOY_BTN21 = 0x40000124,
+		BC_JOY_BTN22 = 0x40000125,
+		BC_JOY_BTN23 = 0x40000126,
+		BC_JOY_BTN24 = 0x40000127,
+		BC_JOY_BTN25 = 0x40000128,
+		BC_JOY_BTN26 = 0x40000129,
+		BC_JOY_BTN27 = 0x4000012A,
+		BC_JOY_BTN28 = 0x4000012B,
+		BC_JOY_BTN29 = 0x4000012C,
+		BC_JOY_BTN30 = 0x4000012D,
+		BC_JOY_BTN31 = 0x4000012E,
+		BC_JOY_BTN32 = 0x4000012F,
+		BC_Count = 0x00000130,
+		BC_NumKeys = 0xEE, // IMPORTANT: Make sure to update these if you modify the values above
+		BC_NumMouse = 0x20,
+		BC_NumJoy = 0x20,
+	};
+
+	struct ButtonEvent
+	{
+	public:
+		ButtonEvent()
+			:mIsUsed(false)
+		{ }
+
+		ButtonCode buttonCode;
+
+		bool isKeyboard() const { return (buttonCode & 0xC0000000) == 0; }
+		bool isMouse() const { return (buttonCode & 0x80000000) != 0; }
+		bool isJoystick() const { return (buttonCode & 0x40000000) != 0; }
+
+		bool isUsed() const { return mIsUsed; }
+		void markAsUsed() const { mIsUsed = true; }
+	private:
+		mutable bool mIsUsed;
+	};
+
+	struct MouseEvent
+	{
+	public:
+		MouseEvent()
+			:mIsUsed(false)
+		{ }
+
+		Int2 screenPos;
+
+		bool isUsed() const { return mIsUsed; }
+		void markAsUsed() const { mIsUsed = true; }
+
+	private:
+		mutable bool mIsUsed;
+	};
+
+	struct TextInputEvent
+	{
+	public:
+		TextInputEvent()
+			:mIsUsed(false)
+		{ }
+
+		UINT32 textChar;
+
+		bool isUsed() const { return mIsUsed; }
+		void markAsUsed() const { mIsUsed = true; }
+
+	private:
+		mutable bool mIsUsed;
+	};
+}

+ 0 - 235
CamelotCore/Include/CmInputHandler.h

@@ -1,235 +0,0 @@
-#pragma once
-
-#include "CmPrerequisites.h"
-#include <boost/signal.hpp>
-#include "CmInt2.h"
-
-namespace CamelotFramework
-{
-	// Note: These KeyCodes are only keyboard scan codes. This means that exact scan code identifier might 
-	// not correspond to that exact character on users keyboard, depending on users input locale. 
-	// Only for US locale will these scan code names will match the actual keyboard input. Think of the US key
-	// code names as only a convenience for more easily identifying which location on the keyboard a scan code represents.
-	enum KeyCode
-	{
-		KC_UNASSIGNED  = 0x00,
-		KC_ESCAPE      = 0x01,
-		KC_1           = 0x02,
-		KC_2           = 0x03,
-		KC_3           = 0x04,
-		KC_4           = 0x05,
-		KC_5           = 0x06,
-		KC_6           = 0x07,
-		KC_7           = 0x08,
-		KC_8           = 0x09,
-		KC_9           = 0x0A,
-		KC_0           = 0x0B,
-		KC_MINUS       = 0x0C,    // - on main keyboard
-		KC_EQUALS      = 0x0D,
-		KC_BACK        = 0x0E,    // backspace
-		KC_TAB         = 0x0F,
-		KC_Q           = 0x10,
-		KC_W           = 0x11,
-		KC_E           = 0x12,
-		KC_R           = 0x13,
-		KC_T           = 0x14,
-		KC_Y           = 0x15,
-		KC_U           = 0x16,
-		KC_I           = 0x17,
-		KC_O           = 0x18,
-		KC_P           = 0x19,
-		KC_LBRACKET    = 0x1A,
-		KC_RBRACKET    = 0x1B,
-		KC_RETURN      = 0x1C,    // Enter on main keyboard
-		KC_LCONTROL    = 0x1D,
-		KC_A           = 0x1E,
-		KC_S           = 0x1F,
-		KC_D           = 0x20,
-		KC_F           = 0x21,
-		KC_G           = 0x22,
-		KC_H           = 0x23,
-		KC_J           = 0x24,
-		KC_K           = 0x25,
-		KC_L           = 0x26,
-		KC_SEMICOLON   = 0x27,
-		KC_APOSTROPHE  = 0x28,
-		KC_GRAVE       = 0x29,    // accent
-		KC_LSHIFT      = 0x2A,
-		KC_BACKSLASH   = 0x2B,
-		KC_Z           = 0x2C,
-		KC_X           = 0x2D,
-		KC_C           = 0x2E,
-		KC_V           = 0x2F,
-		KC_B           = 0x30,
-		KC_N           = 0x31,
-		KC_M           = 0x32,
-		KC_COMMA       = 0x33,
-		KC_PERIOD      = 0x34,    // . on main keyboard
-		KC_SLASH       = 0x35,    // / on main keyboard
-		KC_RSHIFT      = 0x36,
-		KC_MULTIPLY    = 0x37,    // * on numeric keypad
-		KC_LMENU       = 0x38,    // left Alt
-		KC_SPACE       = 0x39,
-		KC_CAPITAL     = 0x3A,
-		KC_F1          = 0x3B,
-		KC_F2          = 0x3C,
-		KC_F3          = 0x3D,
-		KC_F4          = 0x3E,
-		KC_F5          = 0x3F,
-		KC_F6          = 0x40,
-		KC_F7          = 0x41,
-		KC_F8          = 0x42,
-		KC_F9          = 0x43,
-		KC_F10         = 0x44,
-		KC_NUMLOCK     = 0x45,
-		KC_SCROLL      = 0x46,    // Scroll Lock
-		KC_NUMPAD7     = 0x47,
-		KC_NUMPAD8     = 0x48,
-		KC_NUMPAD9     = 0x49,
-		KC_SUBTRACT    = 0x4A,    // - on numeric keypad
-		KC_NUMPAD4     = 0x4B,
-		KC_NUMPAD5     = 0x4C,
-		KC_NUMPAD6     = 0x4D,
-		KC_ADD         = 0x4E,    // + on numeric keypad
-		KC_NUMPAD1     = 0x4F,
-		KC_NUMPAD2     = 0x50,
-		KC_NUMPAD3     = 0x51,
-		KC_NUMPAD0     = 0x52,
-		KC_DECIMAL     = 0x53,    // . on numeric keypad
-		KC_OEM_102     = 0x56,    // < > | on UK/Germany keyboards
-		KC_F11         = 0x57,
-		KC_F12         = 0x58,
-		KC_F13         = 0x64,    //                     (NEC PC98)
-		KC_F14         = 0x65,    //                     (NEC PC98)
-		KC_F15         = 0x66,    //                     (NEC PC98)
-		KC_KANA        = 0x70,    // (Japanese keyboard)
-		KC_ABNT_C1     = 0x73,    // / ? on Portugese (Brazilian) keyboards
-		KC_CONVERT     = 0x79,    // (Japanese keyboard)
-		KC_NOCONVERT   = 0x7B,    // (Japanese keyboard)
-		KC_YEN         = 0x7D,    // (Japanese keyboard)
-		KC_ABNT_C2     = 0x7E,    // Numpad . on Portugese (Brazilian) keyboards
-		KC_NUMPADEQUALS= 0x8D,    // = on numeric keypad (NEC PC98)
-		KC_PREVTRACK   = 0x90,    // Previous Track (KC_CIRCUMFLEX on Japanese keyboard)
-		KC_AT          = 0x91,    //                     (NEC PC98)
-		KC_COLON       = 0x92,    //                     (NEC PC98)
-		KC_UNDERLINE   = 0x93,    //                     (NEC PC98)
-		KC_KANJI       = 0x94,    // (Japanese keyboard)
-		KC_STOP        = 0x95,    //                     (NEC PC98)
-		KC_AX          = 0x96,    //                     (Japan AX)
-		KC_UNLABELED   = 0x97,    //                        (J3100)
-		KC_NEXTTRACK   = 0x99,    // Next Track
-		KC_NUMPADENTER = 0x9C,    // Enter on numeric keypad
-		KC_RCONTROL    = 0x9D,
-		KC_MUTE        = 0xA0,    // Mute
-		KC_CALCULATOR  = 0xA1,    // Calculator
-		KC_PLAYPAUSE   = 0xA2,    // Play / Pause
-		KC_MEDIASTOP   = 0xA4,    // Media Stop
-		KC_VOLUMEDOWN  = 0xAE,    // Volume -
-		KC_VOLUMEUP    = 0xB0,    // Volume +
-		KC_WEBHOME     = 0xB2,    // Web home
-		KC_NUMPADCOMMA = 0xB3,    // , on numeric keypad (NEC PC98)
-		KC_DIVIDE      = 0xB5,    // / on numeric keypad
-		KC_SYSRQ       = 0xB7,
-		KC_RMENU       = 0xB8,    // right Alt
-		KC_PAUSE       = 0xC5,    // Pause
-		KC_HOME        = 0xC7,    // Home on arrow keypad
-		KC_UP          = 0xC8,    // UpArrow on arrow keypad
-		KC_PGUP        = 0xC9,    // PgUp on arrow keypad
-		KC_LEFT        = 0xCB,    // LeftArrow on arrow keypad
-		KC_RIGHT       = 0xCD,    // RightArrow on arrow keypad
-		KC_END         = 0xCF,    // End on arrow keypad
-		KC_DOWN        = 0xD0,    // DownArrow on arrow keypad
-		KC_PGDOWN      = 0xD1,    // PgDn on arrow keypad
-		KC_INSERT      = 0xD2,    // Insert on arrow keypad
-		KC_DELETE      = 0xD3,    // Delete on arrow keypad
-		KC_LWIN        = 0xDB,    // Left Windows key
-		KC_RWIN        = 0xDC,    // Right Windows key
-		KC_APPS        = 0xDD,    // AppMenu key
-		KC_POWER       = 0xDE,    // System Power
-		KC_SLEEP       = 0xDF,    // System Sleep
-		KC_WAKE        = 0xE3,    // System Wake
-		KC_WEBSEARCH   = 0xE5,    // Web Search
-		KC_WEBFAVORITES= 0xE6,    // Web Favorites
-		KC_WEBREFRESH  = 0xE7,    // Web Refresh
-		KC_WEBSTOP     = 0xE8,    // Web Stop
-		KC_WEBFORWARD  = 0xE9,    // Web Forward
-		KC_WEBBACK     = 0xEA,    // Web Back
-		KC_MYCOMPUTER  = 0xEB,    // My Computer
-		KC_MAIL        = 0xEC,    // Mail
-		KC_MEDIASELECT = 0xED,     // Media Select
-		KC_Count
-	};
-
-	enum MouseButton
-	{
-		MB_Left = 0, MB_Right, MB_Middle,
-		MB_Button3, MB_Button4,	MB_Button5, MB_Button6,	MB_Button7, 
-		MB_Button8, MB_Button9, MB_Button10, MB_Button11, MB_Button12, 
-		MB_Button13, MB_Button14, MB_Button15, MB_Button16, MB_Button17,
-		MB_Button18, MB_Button19, MB_Button20, MB_Count
-	};
-
-	struct KeyEvent
-	{
-	public:
-		KeyEvent()
-			:mIsUsed(false)
-		{ }
-
-		KeyCode keyCode;
-		UINT32 textChar;
-
-		bool isUsed() const { return mIsUsed; }
-		void markAsUsed() const { mIsUsed = true; }
-	private:
-		mutable bool mIsUsed;
-	};
-
-	struct MouseEvent
-	{
-	public:
-		MouseEvent()
-			:mIsUsed(false)
-		{ }
-
-		Int2 coords;
-		Int2 relCoords;
-
-		int z;
-		int relZ;
-
-		bool isUsed() const { return mIsUsed; }
-		void markAsUsed() const { mIsUsed = true; }
-
-	private:
-		mutable bool mIsUsed;
-	};
-
-	/**
-	 * @brief	Represents a specific way of acquiring low-level input. InputManager (which provides a higher level input)
-	 * 			must have at least one InputHandler attached. Attach events handler to the provided signals to handle input.
-	 */
-	class CM_EXPORT InputHandler
-	{
-	public:
-		InputHandler() {}
-		virtual ~InputHandler() {}
-
-		boost::signal<void(const KeyEvent&)> onKeyDown;
-		boost::signal<void(const KeyEvent&)> onKeyUp;
-
-		boost::signal<void(const MouseEvent&)> onMouseMoved;
-		boost::signal<void(const MouseEvent&, MouseButton)> onMouseDown;
-		boost::signal<void(const MouseEvent&, MouseButton)> onMouseUp;
-
-		/**
-		 * @brief	Called every frame by InputManager. Capture input here if needed.
-		 */
-		virtual void update() {}
-
-		/**
-		 * @brief	Called by InputManager whenever window in focus changes.
-		 */
-		virtual void inputWindowChanged(const RenderWindow& win) {}
-	};
-}

+ 54 - 0
CamelotCore/Include/CmOSInputHandler.h

@@ -0,0 +1,54 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+#include <boost/signal.hpp>
+#include "CmInt2.h"	
+
+namespace CamelotFramework
+{
+	/**
+		* @brief	Represents a specific way of acquiring OS input. InputManager (which provides a higher level input)
+		* 			must have at least one OSInputHandler attached. Attach events handler to the provided signals to handle input.
+		* 			
+		* @note		Unlike RawInputHandler this class receives input from the operating system, and is used for receiving
+		* 			text input, cursor position and similar.
+		*/
+	class CM_EXPORT OSInputHandler
+	{
+	public:
+		OSInputHandler();
+		virtual ~OSInputHandler();
+
+		boost::signal<void(UINT32)> onCharInput;
+		boost::signal<void(const Int2&)> onMouseMoved;
+
+		/**
+			* @brief	Called every frame by InputManager. Capture input here if needed.
+			*/
+		virtual void update();
+
+		/**
+			* @brief	Called by InputManager whenever window in focus changes.
+			*/
+		virtual void inputWindowChanged(const RenderWindow& win) {}
+
+	private:
+		CM_MUTEX(mOSInputMutex);
+		Int2 mLastMousePos;
+		Int2 mMousePosition;
+		WString mInputString;
+
+		boost::signals::connection mCharInputConn;
+		boost::signals::connection mMouseMovedConn;
+
+		/**
+		 * @brief	Called from the message loop.
+		 */
+		void charInput(UINT32 character);
+
+		/**
+		 * @brief	Called from the message loop.
+		 */
+		void mouseMoved(const Int2& mousePos);
+	};
+}

+ 1 - 2
CamelotCore/Include/CmPrerequisites.h

@@ -127,7 +127,7 @@ namespace CamelotFramework {
     class VertexData;
     class VertexData;
     class VertexDeclaration;
     class VertexDeclaration;
 	class Input;
 	class Input;
-	class InputHandler;
+	class RawInputHandler;
 	class Renderer;
 	class Renderer;
 	class RendererFactory;
 	class RendererFactory;
 	class WorkQueue;
 	class WorkQueue;
@@ -224,7 +224,6 @@ namespace CamelotFramework
 	typedef std::shared_ptr<ImportOptions> ImportOptionsPtr;
 	typedef std::shared_ptr<ImportOptions> ImportOptionsPtr;
 	typedef std::shared_ptr<const ImportOptions> ConstImportOptionsPtr;
 	typedef std::shared_ptr<const ImportOptions> ConstImportOptionsPtr;
 	typedef std::shared_ptr<Font> FontPtr;
 	typedef std::shared_ptr<Font> FontPtr;
-	typedef std::shared_ptr<InputHandler> InputHandlerPtr;
 	typedef std::shared_ptr<GpuResource> GpuResourcePtr;
 	typedef std::shared_ptr<GpuResource> GpuResourcePtr;
 }
 }
 
 

+ 64 - 0
CamelotCore/Include/CmRawInputHandler.h

@@ -0,0 +1,64 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+#include "CmInputFwd.h"
+#include <boost/signal.hpp>
+#include "CmInt2.h"
+
+namespace CamelotFramework
+{
+	struct RawAxisState
+	{
+		Int2 rel;
+		Int2 abs;
+	};
+
+	enum class RawInputAxis
+	{
+		Mouse_XY,
+		Mouse_Z,
+		Joy_1,
+		Joy_2,
+		Joy_3,
+		Joy_4,
+		Joy_5,
+		Joy_6,
+		Joy_7,
+		Joy_8,
+		Joy_9,
+		Joy_10,
+		Joy_11,
+		Joy_12,
+		Joy_13,
+		Joy_14,
+		Joy_15,
+		Joy_16,
+		Count
+	};
+
+	/**
+	 * @brief	Represents a specific way of acquiring low-level input. InputManager (which provides a higher level input)
+	 * 			must have at least one InputHandler attached. Attach events handler to the provided signals to handle input.
+	 */
+	class CM_EXPORT RawInputHandler
+	{
+	public:
+		RawInputHandler() {}
+		virtual ~RawInputHandler() {}
+
+		boost::signal<void(ButtonCode)> onButtonDown;
+		boost::signal<void(ButtonCode)> onButtonUp;
+
+		boost::signal<void(const RawAxisState&, RawInputAxis)> onAxisMoved;
+
+		/**
+		 * @brief	Called every frame by InputManager. Capture input here if needed.
+		 */
+		virtual void update() {}
+
+		/**
+		 * @brief	Called by InputManager whenever window in focus changes.
+		 */
+		virtual void inputWindowChanged(const RenderWindow& win) {}
+	};
+}

+ 5 - 0
CamelotCore/Include/CmWindowEventUtilities.h

@@ -29,6 +29,7 @@ THE SOFTWARE.
 #define __OgreWindowEventUtils_H__
 #define __OgreWindowEventUtils_H__
 
 
 #include "CmPrerequisites.h"
 #include "CmPrerequisites.h"
+#include <boost/signals.hpp>
 
 
 #if CM_PLATFORM == CM_PLATFORM_WIN32
 #if CM_PLATFORM == CM_PLATFORM_WIN32
 #  define WIN32_LEAN_AND_MEAN
 #  define WIN32_LEAN_AND_MEAN
@@ -36,6 +37,7 @@ THE SOFTWARE.
 #	define NOMINMAX // required to stop windows.h messing up std::min
 #	define NOMINMAX // required to stop windows.h messing up std::min
 #  endif
 #  endif
 #  include <windows.h>
 #  include <windows.h>
+#  include <windowsx.h>
 #elif CM_PLATFORM == CM_PLATFORM_APPLE && !defined(__LP64__)
 #elif CM_PLATFORM == CM_PLATFORM_APPLE && !defined(__LP64__)
 #  include <Carbon/Carbon.h>
 #  include <Carbon/Carbon.h>
 #endif
 #endif
@@ -87,6 +89,9 @@ namespace CamelotFramework
 
 
 		typedef Vector<RenderWindow*>::type Windows;
 		typedef Vector<RenderWindow*>::type Windows;
 		static Windows _msWindows;
 		static Windows _msWindows;
+
+		static boost::signal<void(const Int2&)> onMouseMoved;
+		static boost::signal<void(UINT32)> onCharInput;
 	};
 	};
 	/** @} */
 	/** @} */
 	/** @} */
 	/** @} */

+ 4 - 2
CamelotCore/Include/Win32/CmCursorImpl.h

@@ -26,8 +26,10 @@ namespace CamelotFramework
 		Cursor();
 		Cursor();
 		~Cursor();
 		~Cursor();
 
 
-		static Int2 getScreenPosition();
-		static void setScreenPosition(const Int2& pos);
+		/**
+		 * @brief	Moves the cursor to the specified screen position.
+		 */
+		static void setPosition(const Int2& screenPos);
 
 
 		static void clipToWindow(const RenderWindow& window);
 		static void clipToWindow(const RenderWindow& window);
 		static void clipToRect(const Rect& screenRect);
 		static void clipToRect(const Rect& screenRect);

+ 75 - 41
CamelotCore/Source/CmInput.cpp

@@ -12,7 +12,7 @@ namespace CamelotFramework
 	const float Input::WEIGHT_MODIFIER = 0.5f;
 	const float Input::WEIGHT_MODIFIER = 0.5f;
 
 
 	Input::Input()
 	Input::Input()
-		:mSmoothHorizontalAxis(0.0f), mSmoothVerticalAxis(0.0f), mCurrentBufferIdx(0), mMouseLastRel(0, 0), mInputHandler(nullptr)
+		:mSmoothHorizontalAxis(0.0f), mSmoothVerticalAxis(0.0f), mCurrentBufferIdx(0), mMouseLastRel(0, 0), mRawInputHandler(nullptr)
 	{ 
 	{ 
 		mHorizontalHistoryBuffer = cm_newN<float>(HISTORY_BUFFER_SIZE);
 		mHorizontalHistoryBuffer = cm_newN<float>(HISTORY_BUFFER_SIZE);
 		mVerticalHistoryBuffer = cm_newN<float>(HISTORY_BUFFER_SIZE);
 		mVerticalHistoryBuffer = cm_newN<float>(HISTORY_BUFFER_SIZE);
@@ -25,11 +25,13 @@ namespace CamelotFramework
 			mTimesHistoryBuffer[i] = 0.0f;
 			mTimesHistoryBuffer[i] = 0.0f;
 		}
 		}
 
 
-		for(int i = 0; i < MB_Count; i++)
-			mMouseButtonState[i] = false;
-
-		for(int i = 0; i < KC_Count; i++)
+		for(int i = 0; i < BC_Count; i++)
 			mKeyState[i] = false;
 			mKeyState[i] = false;
+
+		mOSInputHandler = cm_shared_ptr<OSInputHandler>();
+
+		mOSInputHandler->onCharInput.connect(boost::bind(&Input::charInput, this, _1));
+		mOSInputHandler->onMouseMoved.connect(boost::bind(&Input::mouseMoved, this, _1));
 	}
 	}
 
 
 	Input::~Input()
 	Input::~Input()
@@ -39,71 +41,108 @@ namespace CamelotFramework
 		cm_deleteN(mTimesHistoryBuffer, HISTORY_BUFFER_SIZE);
 		cm_deleteN(mTimesHistoryBuffer, HISTORY_BUFFER_SIZE);
 	}
 	}
 
 
-	void Input::registerInputHandler(InputHandlerPtr inputHandler)
+	void Input::registerRawInputHandler(std::shared_ptr<RawInputHandler> inputHandler)
 	{
 	{
-		if(mInputHandler != inputHandler)
+		if(mRawInputHandler != inputHandler)
 		{
 		{
-			mInputHandler = inputHandler;
+			mRawInputHandler = inputHandler;
 
 
-			if(mInputHandler != nullptr)
+			if(mRawInputHandler != nullptr)
 			{
 			{
-				mInputHandler->onKeyDown.connect(boost::bind(&Input::keyDown, this, _1));
-				mInputHandler->onKeyUp.connect(boost::bind(&Input::keyUp, this, _1));
+				mRawInputHandler->onButtonDown.connect(boost::bind(&Input::buttonDown, this, _1));
+				mRawInputHandler->onButtonUp.connect(boost::bind(&Input::buttonUp, this, _1));
 
 
-				mInputHandler->onMouseMoved.connect(boost::bind(&Input::mouseMoved, this, _1));
-				mInputHandler->onMouseDown.connect(boost::bind(&Input::mouseDown, this, _1, _2));
-				mInputHandler->onMouseUp.connect(boost::bind(&Input::mouseUp, this, _1, _2));
+				mRawInputHandler->onAxisMoved.connect(boost::bind(&Input::axisMoved, this, _1, _2));
 			}
 			}
 		}
 		}
 	}
 	}
 
 
 	void Input::update()
 	void Input::update()
 	{
 	{
-		if(mInputHandler == nullptr)
+		if(mOSInputHandler == nullptr)
 		{
 		{
-			LOGERR("Input handler not initialized!");
+			LOGERR("OS input handler not initialized!");
 			return;
 			return;
 		}
 		}
+		else
+			mOSInputHandler->update();
 
 
-		mInputHandler->update();
+		if(mRawInputHandler == nullptr)
+		{
+			LOGERR("Raw input handler not initialized!");
+			return;
+		}
+		else
+			mRawInputHandler->update();
 
 
 		updateSmoothInput();
 		updateSmoothInput();
 	}
 	}
 
 
 	void Input::inputWindowChanged(const RenderWindow& win)
 	void Input::inputWindowChanged(const RenderWindow& win)
 	{
 	{
-		if(mInputHandler != nullptr)
-			mInputHandler->inputWindowChanged(win);
+		if(mRawInputHandler != nullptr)
+			mRawInputHandler->inputWindowChanged(win);
+
+		if(mOSInputHandler != nullptr)
+			mOSInputHandler->inputWindowChanged(win);
 	}
 	}
 
 
-	void Input::keyDown(const KeyEvent& event)
+	void Input::buttonDown(ButtonCode code)
 	{
 	{
-		mKeyState[event.keyCode] = true;
-		onKeyDown(event);
+		mKeyState[code & 0x0000FFFF] = true;
+
+		if(!onKeyDown.empty())
+		{
+			ButtonEvent btnEvent;
+			btnEvent.buttonCode = code;
+
+			onKeyDown(btnEvent);
+		}
 	}
 	}
 
 
-	void Input::keyUp(const KeyEvent& event)
+	void Input::buttonUp(ButtonCode code)
 	{
 	{
-		mKeyState[event.keyCode] = false;
-		onKeyUp(event);
+		mKeyState[code & 0x0000FFFF] = false;
+
+		if(!onKeyUp.empty())
+		{
+			ButtonEvent btnEvent;
+			btnEvent.buttonCode = code;
+
+			onKeyUp(btnEvent);
+		}
 	}
 	}
 
 
-	void Input::mouseMoved(const MouseEvent& event)
+	void Input::axisMoved(const RawAxisState& state, RawInputAxis axis)
 	{
 	{
-		onMouseMoved(event);
-		mMouseLastRel = Int2(-event.relCoords.x, -event.relCoords.y);
+		if(axis == RawInputAxis::Mouse_XY)
+			mMouseLastRel = Int2(-state.rel.x, -state.rel.y);
+
+		mAxes[(int)axis] = state;
 	}
 	}
 
 
-	void Input::mouseDown(const MouseEvent& event, MouseButton buttonID)
+	void Input::mouseMoved(const Int2& screenPos)
 	{
 	{
-		mMouseButtonState[buttonID] = true;
-		onMouseDown(event, buttonID);
+		mMouseAbsPos = screenPos;
+
+		if(!onMouseMoved.empty())
+		{
+			MouseEvent mouseEvent;
+			mouseEvent.screenPos = screenPos;
+
+			onMouseMoved(mouseEvent);
+		}
 	}
 	}
 
 
-	void Input::mouseUp(const MouseEvent& event, MouseButton buttonID)
+	void Input::charInput(UINT32 chr)
 	{
 	{
-		mMouseButtonState[buttonID] = false;
-		onMouseUp(event, buttonID);
+		if(!onCharInput.empty())
+		{
+			TextInputEvent textInputEvent;
+			textInputEvent.textChar = chr;
+
+			onCharInput(textInputEvent);
+		}
 	}
 	}
 
 
 	float Input::getHorizontalAxis() const
 	float Input::getHorizontalAxis() const
@@ -116,14 +155,9 @@ namespace CamelotFramework
 		return mSmoothVerticalAxis;
 		return mSmoothVerticalAxis;
 	}
 	}
 
 
-	bool Input::isButtonDown(MouseButton button) const
-	{
-		return mMouseButtonState[button];
-	}
-
-	bool Input::isKeyDown(KeyCode keyCode) const
+	bool Input::isButtonDown(ButtonCode button) const
 	{
 	{
-		return mKeyState[keyCode];
+		return mKeyState[button & 0x0000FFFF];
 	}
 	}
 
 
 	void Input::updateSmoothInput()
 	void Input::updateSmoothInput()

+ 61 - 0
CamelotCore/Source/CmOSInputHandler.cpp

@@ -0,0 +1,61 @@
+#include "CmOSInputHandler.h"
+#include "CmWindowEventUtilities.h"
+
+namespace CamelotFramework
+{
+	OSInputHandler::OSInputHandler()
+	{
+		mCharInputConn = WindowEventUtilities::onCharInput.connect(boost::bind(&OSInputHandler::charInput, this, _1));
+		mMouseMovedConn = WindowEventUtilities::onMouseMoved.connect(boost::bind(&OSInputHandler::mouseMoved, this, _1));
+	}
+
+	OSInputHandler::~OSInputHandler()
+	{
+		mCharInputConn.disconnect();
+		mMouseMovedConn.disconnect();
+	}
+
+	void OSInputHandler::update()
+	{
+		WString inputString;
+		Int2 mousePosition;
+
+		{
+			CM_LOCK_MUTEX(mOSInputMutex);
+			inputString = mInputString;
+			mInputString.clear();
+
+			mousePosition = mMousePosition;
+		}
+
+		if(mousePosition != mLastMousePos)
+		{
+			if(!onMouseMoved.empty())
+				onMouseMoved(mousePosition);
+
+			mLastMousePos = mousePosition;
+		}
+
+		if(!onCharInput.empty())
+		{
+			for(auto& curChar : inputString)
+			{
+				onCharInput((UINT32)curChar);
+			}
+		}
+	}
+
+	void OSInputHandler::charInput(UINT32 character)
+	{
+		CM_LOCK_MUTEX(mOSInputMutex);
+
+		mInputString += character;
+	}
+
+	void OSInputHandler::mouseMoved(const Int2& mousePos)
+	{
+		CM_LOCK_MUTEX(mOSInputMutex);
+
+		mMousePosition = mousePos;
+	}
+}

+ 67 - 0
CamelotCore/Source/CmWindowEventUtilities.cpp

@@ -40,6 +40,8 @@ void GLXProc( CamelotFramework::RenderWindow *win, const XEvent &event );
 using namespace CamelotFramework;
 using namespace CamelotFramework;
 
 
 WindowEventUtilities::Windows WindowEventUtilities::_msWindows;
 WindowEventUtilities::Windows WindowEventUtilities::_msWindows;
+boost::signal<void(const Int2&)> WindowEventUtilities::onMouseMoved;
+boost::signal<void(CamelotFramework::UINT32)> WindowEventUtilities::onCharInput;
 
 
 //--------------------------------------------------------------------------------//
 //--------------------------------------------------------------------------------//
 void WindowEventUtilities::messagePump()
 void WindowEventUtilities::messagePump()
@@ -212,6 +214,71 @@ LRESULT CALLBACK WindowEventUtilities::_WndProc(HWND hWnd, UINT uMsg, WPARAM wPa
 
 
 		return 0;
 		return 0;
 	}
 	}
+	case WM_MOUSEMOVE:
+		{
+			POINT mousePos;
+			
+			mousePos.x = GET_X_LPARAM(lParam);
+			mousePos.y = GET_Y_LPARAM(lParam); 
+
+			ClientToScreen(hWnd, &mousePos);
+
+			if(!onMouseMoved.empty())
+				onMouseMoved(Int2(mousePos.x, mousePos.y));
+
+			return true;
+		}
+	case WM_DEADCHAR:
+	case WM_CHAR:
+		{
+			switch (wParam) 
+			{ 
+			case VK_BACK:
+			case 0x0A:  // linefeed 
+			case 0x0D:  // carriage return 
+			case VK_ESCAPE:
+			case VK_TAB: 
+				break; 
+
+			default:    // displayable character 
+				{
+					UINT8 scanCode = (lParam >> 16) & 0xFF;
+
+					BYTE keyState[256];
+					HKL layout = GetKeyboardLayout(0);
+					if(GetKeyboardState(keyState) == 0)
+						return 0;
+
+					unsigned int vk = MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, layout);
+					if(vk == 0)
+						return 0;
+
+					bool isDeadKey = (MapVirtualKeyEx(vk, MAPVK_VK_TO_CHAR, layout) & (1 << 31)) != 0;
+					if(isDeadKey)
+						return 0;
+
+					wchar_t buff[3] = {0};
+					int numChars = ToUnicodeEx(vk, scanCode, keyState, buff, 3, 0, layout);
+
+					// TODO - I am ignoring dead keys here - primarily because I haven't found a good way of retrieving non-combined dead key
+					// value. ToUnicodeEx and MapVirtualKeyEx only return precombined (i.e. spacing) versions, which can't be combined using other characters.
+					// I need non-combined version so I can use it with FoldString to apply to a certain character.
+
+					UINT32 finalChar = 0;
+					if(numChars == 1)
+						finalChar = buff[0];
+					else
+						return 0;
+
+					if(!onCharInput.empty())
+						onCharInput(finalChar);
+
+					return 0;
+				}
+			} 
+
+			break;
+		}
 	}
 	}
 
 
 	return DefWindowProc( hWnd, uMsg, wParam, lParam );
 	return DefWindowProc( hWnd, uMsg, wParam, lParam );

+ 1 - 14
CamelotCore/Source/Win32/CmCursorImpl.cpp

@@ -26,21 +26,8 @@ namespace CamelotFramework
 	NativeCursorData Cursor::mCursor;
 	NativeCursorData Cursor::mCursor;
 	bool Cursor::mUsingCustom = false;
 	bool Cursor::mUsingCustom = false;
 
 
-	Int2 Cursor::getScreenPosition()
+	void Cursor::setPosition(const Int2& screenPos)
 	{
 	{
-		POINT screenPos;
-		GetCursorPos(&screenPos);
-
-		return Int2(screenPos.x, screenPos.y);
-	}
-
-	void Cursor::setScreenPosition(const Int2& pos)
-	{
-		POINT screenPos;
-
-		screenPos.x = pos.x;
-		screenPos.y = pos.y;
-
 		SetCursorPos(screenPos.x, screenPos.y);
 		SetCursorPos(screenPos.x, screenPos.y);
 	}
 	}
 
 

+ 5 - 2
CamelotOISInput/Include/CmInputHandlerOIS.h

@@ -1,7 +1,7 @@
 #pragma once
 #pragma once
 
 
 #include "CmOISPrerequisites.h"
 #include "CmOISPrerequisites.h"
-#include "CmInputHandler.h"
+#include "CmRawInputHandler.h"
 
 
 #include <OIS/OISEvents.h>
 #include <OIS/OISEvents.h>
 #include <OIS/OISInputManager.h>
 #include <OIS/OISInputManager.h>
@@ -10,7 +10,7 @@
 
 
 namespace CamelotFramework
 namespace CamelotFramework
 {
 {
-	class CM_OIS_EXPORT InputHandlerOIS : public InputHandler, public OIS::KeyListener, public OIS::MouseListener
+	class CM_OIS_EXPORT InputHandlerOIS : public RawInputHandler, public OIS::KeyListener, public OIS::MouseListener
 	{
 	{
 	public:
 	public:
 		InputHandlerOIS(unsigned int hWnd);
 		InputHandlerOIS(unsigned int hWnd);
@@ -29,5 +29,8 @@ namespace CamelotFramework
 
 
 		virtual void update();
 		virtual void update();
 		virtual void inputWindowChanged(const RenderWindow& win);
 		virtual void inputWindowChanged(const RenderWindow& win);
+
+		ButtonCode keyCodeToButtonCode(OIS::KeyCode keyCode) const;
+		ButtonCode mouseButtonToButtonCode(OIS::MouseButtonID mouseBtn) const;
 	};
 	};
 }
 }

+ 26 - 28
CamelotOISInput/Source/CmInputHandlerOIS.cpp

@@ -31,7 +31,7 @@ namespace CamelotFramework
 		catch(OIS::Exception &e)
 		catch(OIS::Exception &e)
 		{
 		{
 			std::cout << e.eText << std::endl;
 			std::cout << e.eText << std::endl;
-		} 
+		}
 
 
 		mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject(OIS::OISKeyboard, true));
 		mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject(OIS::OISKeyboard, true));
 		mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject(OIS::OISMouse, true));
 		mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject(OIS::OISMouse, true));
@@ -76,56 +76,54 @@ namespace CamelotFramework
 
 
 	bool InputHandlerOIS::keyPressed(const OIS::KeyEvent &arg)
 	bool InputHandlerOIS::keyPressed(const OIS::KeyEvent &arg)
 	{
 	{
-		KeyEvent event;
-		event.keyCode = (KeyCode)(int)arg.key;
-		event.textChar = arg.text;
-
-		onKeyDown(event);
+		onButtonDown(keyCodeToButtonCode(arg.key));
 		return true;
 		return true;
 	}
 	}
 
 
 	bool InputHandlerOIS::keyReleased(const OIS::KeyEvent& arg)
 	bool InputHandlerOIS::keyReleased(const OIS::KeyEvent& arg)
 	{
 	{
-		KeyEvent event;
-		event.keyCode = (KeyCode)(int)arg.key;
-		event.textChar = arg.text;
-
-		onKeyUp(event);
+		onButtonUp(keyCodeToButtonCode(arg.key));
 		return true;
 		return true;
 	}
 	}
 
 
 	bool InputHandlerOIS::mouseMoved(const OIS::MouseEvent& arg)
 	bool InputHandlerOIS::mouseMoved(const OIS::MouseEvent& arg)
 	{
 	{
-		MouseEvent event;
-		event.coords = Int2(arg.state.X.abs, arg.state.Y.abs);
-		event.relCoords = Int2(arg.state.X.rel, arg.state.Y.rel);
-		event.z = arg.state.Z.abs;
-		event.relZ = arg.state.Z.rel;
+		RawAxisState xyState;
+		xyState.abs = Int2(arg.state.X.abs, arg.state.Y.abs);
+		xyState.rel = Int2(arg.state.X.rel, arg.state.Y.rel);
+
+		onAxisMoved(xyState, RawInputAxis::Mouse_XY);
+
+		RawAxisState zState;
+		zState.abs = Int2(arg.state.Z.abs, 0);
+		zState.rel = Int2(arg.state.Z.rel, 0);
+
+		onAxisMoved(zState, RawInputAxis::Mouse_Z);
 
 
-		onMouseMoved(event);
 		return true;
 		return true;
 	}
 	}
 
 
 	bool InputHandlerOIS::mousePressed(const OIS::MouseEvent& arg, OIS::MouseButtonID id)
 	bool InputHandlerOIS::mousePressed(const OIS::MouseEvent& arg, OIS::MouseButtonID id)
 	{
 	{
-		MouseEvent event;
-		event.coords = Int2(arg.state.X.abs, arg.state.Y.abs);
-		event.relCoords = Int2(arg.state.X.rel, arg.state.Y.rel);
-		event.z = arg.state.Z.abs;
-		event.relZ = arg.state.Z.rel;
+		onButtonDown(mouseButtonToButtonCode(id));
 
 
-		onMouseDown(event, (MouseButton)(int)id);
 		return true;
 		return true;
 	}
 	}
 
 
 	bool InputHandlerOIS::mouseReleased(const OIS::MouseEvent& arg, OIS::MouseButtonID id)
 	bool InputHandlerOIS::mouseReleased(const OIS::MouseEvent& arg, OIS::MouseButtonID id)
 	{
 	{
-		MouseEvent event;
-		event.coords = Int2(arg.state.X.abs, arg.state.Y.abs);
-		event.relCoords = Int2(0, 0);
-		event.z = arg.state.Z.abs;
+		onButtonUp(mouseButtonToButtonCode(id));
 
 
-		onMouseUp(event, (MouseButton)(int)id);
 		return true;
 		return true;
 	}
 	}
+
+	ButtonCode InputHandlerOIS::keyCodeToButtonCode(OIS::KeyCode keyCode) const
+	{
+		return (ButtonCode)keyCode;
+	}
+
+	ButtonCode InputHandlerOIS::mouseButtonToButtonCode(OIS::MouseButtonID mouseBtn) const
+	{
+		return (ButtonCode)(((int)mouseBtn + BC_NumKeys) | 0x80000000);
+	}
 }
 }

+ 2 - 2
CamelotOISInput/Source/CmOISPlugin.cpp

@@ -16,9 +16,9 @@ namespace CamelotFramework
 		// TODO - Window handles in Windows are 64 bits when compiled as x64, but OIS only accepts a 32bit value. Is this okay?
 		// TODO - Window handles in Windows are 64 bits when compiled as x64, but OIS only accepts a 32bit value. Is this okay?
 		UINT32 windowId = (UINT32)gApplication().getAppWindowId();
 		UINT32 windowId = (UINT32)gApplication().getAppWindowId();
 
 
-		InputHandlerPtr inputHandler = cm_shared_ptr<InputHandlerOIS>(windowId);
+		std::shared_ptr<RawInputHandler> inputHandler = cm_shared_ptr<InputHandlerOIS>(windowId);
 
 
-		gInput().registerInputHandler(inputHandler);
+		gInput().registerRawInputHandler(inputHandler);
 
 
 		return nullptr;
 		return nullptr;
 	}
 	}

+ 8 - 0
Notes.txt

@@ -106,6 +106,14 @@ Questions/Notes:
  5. This guy: http://home.comcast.net/~tom_forsyth/blog.wiki.html#%5B%5BRenderstate%20change%20costs%5D%5D (who's a driver programmer) sorts all opaque objects based on shader/state
  5. This guy: http://home.comcast.net/~tom_forsyth/blog.wiki.html#%5B%5BRenderstate%20change%20costs%5D%5D (who's a driver programmer) sorts all opaque objects based on shader/state
     into buckets, and then orders elements in these bucks in front to back order. This gives him best of two worlds, early z rejection and low state changes.
     into buckets, and then orders elements in these bucks in front to back order. This gives him best of two worlds, early z rejection and low state changes.
 
 
+<<<<Input System>>>>
+ - Input is currently ignoring all axes except for mouse axes
+ - Remove/Improve smoothing
+ - Add ability to get raw or smoothed axis input for any axis (currently you can only get mouse X and Y axes)
+ - Allow the user to map axes to custom keys. e.g. Left/right axis can have A and D keys where A returns -1, and D 1
+ - Add a way to handle multiple devices (e.g. 2 or more joysticks)
+ - Hook up OIS joystick callbacks and test joysticks
+
 <<<<DirectDraw>>>>
 <<<<DirectDraw>>>>
  - Used for quickly drawing something, usually for debug and editor purposes.
  - Used for quickly drawing something, usually for debug and editor purposes.
  - It consists of methods like: DrawLine, DrawPolygon, DrawCube, DrawSphere, etc.
  - It consists of methods like: DrawLine, DrawPolygon, DrawCube, DrawSphere, etc.

+ 6 - 18
TODO.txt

@@ -23,29 +23,17 @@ GUIWidget::updateMeshes leaks. If I leave the game running I can see memory cont
 
 
 /************** INPUT REFACTOR *********************/
 /************** INPUT REFACTOR *********************/
 
 
-Remagine render thread:
- - Its main loop is in CmApplication
- - Rename it to CoreThread
-
-Reimagine input:
- - Text input should come from main loop instead of from OIS. This way I can use key repeat and similar functions
-
-I should separate actual games input and text/cursor input. Key presses used for text and absolute cursor position should be provided separately.
- - Main loop updates gInput with current text string (mutex protected), which gets flushed character by character when update() is called
- - Same thing with absolute cursor position
- - Also it will call focusChange as it does now
-
-Add separate classes:
- RawInputHandler (transform existing InputHandler) - Called from main thread
- OSInputHandler (new class) - Called from core thread
-
 AT THE END DONT FORGET:
 AT THE END DONT FORGET:
  Compile new OIS for all other build types (also update libs and includes)
  Compile new OIS for all other build types (also update libs and includes)
 
 
-More concrete changes:
+DO LATER:
+ - Modifiyng Input focusChange so it gets called from WindowManager
+  - After I do remove the HWND == 0 check from Input
  - onMovedOrResized is still used by Viewport
  - onMovedOrResized is still used by Viewport
  - Replace list of windows in WIndowEventUtilities with WindowManagers list. No need to keep two lists I think
  - Replace list of windows in WIndowEventUtilities with WindowManagers list. No need to keep two lists I think
-
+ - Remagine render thread:
+   - Its main loop is in CmApplication
+   - Rename it to CoreThread
 ------------
 ------------
 
 
 How to design OSInputHandler and how does it interact with msg loop?
 How to design OSInputHandler and how does it interact with msg loop?