Browse Source

Refactor: Input system no longer has separate handlers for OS and Raw input, as the distinction is no longer relevant with the removal of OIS dependency

BearishSun 8 years ago
parent
commit
0f89ba7d14

+ 15 - 16
Source/BansheeCore/BsCorePrerequisites.h

@@ -215,31 +215,30 @@ namespace bs
 	static const StringID RenderAPIAny = "AnyRenderAPI";
 	static const StringID RendererAny = "AnyRenderer";
 
-    class Color;
-    class GpuProgram;
-    class GpuProgramManager;
-    class IndexBuffer;
-    class VertexBuffer;
+	class Color;
+	class GpuProgram;
+	class GpuProgramManager;
+	class IndexBuffer;
+	class VertexBuffer;
 	class GpuBuffer;
 	class GpuProgramManager;
 	class GpuProgramFactory;
-    class IndexData;
-    class Pass;
+	class IndexData;
+	class Pass;
 	class Technique;
 	class Shader;
 	class Material;
-    class RenderAPICapabilities;
-    class RenderTarget;
-    class RenderTexture;
-    class RenderWindow;
+	class RenderAPICapabilities;
+	class RenderTarget;
+	class RenderTexture;
+	class RenderWindow;
 	class RenderTargetProperties;
-    class SamplerState;
-    class TextureManager;
-    class Viewport;
-    class VertexDeclaration;
+	class SamplerState;
+	class TextureManager;
+	class Viewport;
+	class VertexDeclaration;
 	class Input;
 	struct PointerEvent;
-	class RawInputHandler;
 	class RendererFactory;
 	class AsyncOp;
 	class HardwareBufferManager;

+ 0 - 4
Source/BansheeCore/CMakeSources.cmake

@@ -83,8 +83,6 @@ set(BS_BANSHEECORE_INC_SCENE
 )
 
 set(BS_BANSHEECORE_INC_INPUT
-	"Input/BsRawInputHandler.h"
-	"Input/BsOSInputHandler.h"
 	"Input/BsInputFwd.h"
 	"Input/BsInput.h"
 	"Input/BsMouse.h"
@@ -434,8 +432,6 @@ set(BS_BANSHEECORE_SRC_MATERIAL
 
 set(BS_BANSHEECORE_SRC_INPUT
 	"Input/BsInput.cpp"
-	"Input/BsOSInputHandler.cpp"
-	"Input/BsRawInputHandler.cpp"
 )
 
 set(BS_BANSHEECORE_INC_LOCALIZATION

+ 5 - 5
Source/BansheeCore/Input/BsGamepad.h

@@ -8,19 +8,19 @@ namespace bs
 {
 	struct GamepadInfo;
 
-	/** Represents a single hardware gamepad. Used by the RawInputHandler to report gamepad input events. */
+	/** Represents a single hardware gamepad. Used by the Input to report gamepad input events. */
 	class BS_CORE_EXPORT Gamepad
 	{
 	public:
 		struct Pimpl;
 
-		Gamepad(const String& name, const GamepadInfo& gamepadInfo, RawInputHandler* owner);
+		Gamepad(const String& name, const GamepadInfo& gamepadInfo, Input* owner);
 		~Gamepad();
 
 		/** Returns the name of the device. */
 		String getName() const { return mName; }
 
-		/** Captures the input since the last call and triggers the events on the parent RawInputHandler. */
+		/** Captures the input since the last call and triggers the events on the parent Input. */
 		void capture();
 
 		/** Minimum allowed value as reported by the axis movement events. */
@@ -29,13 +29,13 @@ namespace bs
 		/** Maximum allowed value as reported by the axis movement events. */
 		static constexpr int MAX_AXIS = 32767;
 	private:
-		friend class RawInputHandler;
+		friend class Input;
 
 		/** Changes the capture context. Should be called when focus is moved to a new window. */
 		void changeCaptureContext(UINT64 windowHandle);
 
 		String mName;
-		RawInputHandler* mOwner;
+		Input* mOwner;
 
 		Pimpl* m;
 	};

+ 395 - 105
Source/BansheeCore/Input/BsInput.cpp

@@ -1,10 +1,11 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "Input/BsInput.h"
+#include "Input/BsMouse.h"
+#include "Input/BsKeyboard.h"
+#include "Input/BsGamepad.h"
 #include "Utility/BsTime.h"
 #include "Math/BsMath.h"
-#include "Math/BsRect2I.h"
-#include "Debug/BsDebug.h"
 #include "Managers/BsRenderWindowManager.h"
 #include "BsCoreApplication.h"
 
@@ -12,6 +13,9 @@ using namespace std::placeholders;
 
 namespace bs
 {
+	// Note: Input polling methods for button/axis could be re-written so their query immediate state
+	// instead of returning cached state from event callbacks. This /might/ result in even less input lag?
+
 	const int Input::HISTORY_BUFFER_SIZE = 10; // Size of buffer used for input smoothing
 	const float Input::WEIGHT_MODIFIER = 0.5f;
 
@@ -22,36 +26,55 @@ namespace bs
 	}
 
 	Input::Input()
-		: mPointerDoubleClicked(false), mLastPositionSet(false)
+		: mPointerDoubleClicked(false), mLastPositionSet(false), mMouseScroll(0.0f), mMouseSmoothingEnabled(false)
+		, mMouse(nullptr), mKeyboard(nullptr)
 	{
 		SPtr<RenderWindow> primaryWindow = gCoreApplication().getPrimaryWindow();
+		primaryWindow->getCustomAttribute("WINDOW", &mWindowHandle);
 
-		UINT64 windowId = 0;
-		primaryWindow->getCustomAttribute("WINDOW", &windowId);
-
-		mOSInputHandler = bs_shared_ptr_new<OSInputHandler>();
-		mRawInputHandler = bs_shared_ptr_new<RawInputHandler>(windowId);
-
-		mOSInputHandler->onCharInput.connect(std::bind(&Input::charInput, this, _1));
-		mOSInputHandler->onCursorMoved.connect(std::bind(&Input::cursorMoved, this, _1));
-		mOSInputHandler->onCursorPressed.connect(std::bind(&Input::cursorPressed, this, _1));
-		mOSInputHandler->onCursorReleased.connect(std::bind(&Input::cursorReleased, this, _1));
-		mOSInputHandler->onDoubleClick.connect(std::bind(&Input::cursorDoubleClick, this, _1));
-		mOSInputHandler->onInputCommand.connect(std::bind(&Input::inputCommandEntered, this, _1));
-
-		mRawInputHandler->onButtonDown.connect(std::bind(&Input::buttonDown, this, _1, _2, _3));
-		mRawInputHandler->onButtonUp.connect(std::bind(&Input::buttonUp, this, _1, _2, _3));
+		// Subscribe to events
+		mCharInputConn = Platform::onCharInput.connect(std::bind(&Input::charInput, this, _1));
+		mCursorMovedConn = Platform::onCursorMoved.connect(std::bind(&Input::cursorMoved, this, _1, _2));
+		mCursorPressedConn = Platform::onCursorButtonPressed.connect(std::bind(&Input::cursorPressed, this, _1, _2, _3));
+		mCursorReleasedConn = Platform::onCursorButtonReleased.connect(std::bind(&Input::cursorReleased, this, _1, _2, _3));
+		mCursorDoubleClickConn = Platform::onCursorDoubleClick.connect(std::bind(&Input::cursorDoubleClick, this, _1, _2));
+		mInputCommandConn = Platform::onInputCommand.connect(std::bind(&Input::inputCommandEntered, this, _1));
 
-		mRawInputHandler->onAxisMoved.connect(std::bind(&Input::axisMoved, this, _1, _2, _3));
+		mMouseWheelScrolledConn  = Platform::onMouseWheelScrolled.connect(std::bind(&Input::mouseWheelScrolled, this, _1));
 
 		RenderWindowManager::instance().onFocusGained.connect(std::bind(&Input::inputWindowChanged, this, _1));
 
 		for (int i = 0; i < 3; i++)
 			mPointerButtonStates[i] = ButtonState::Off;
+
+		// Mouse smoothing
+		mMouseSampleAccumulator[0] = 0;
+		mMouseSampleAccumulator[1] = 0;
+		mTotalMouseSamplingTime[0] = 1.0f / 125.0f; // Use 125Hz as initial pooling rate for mice
+		mTotalMouseSamplingTime[1] = 1.0f / 125.0f;
+		mTotalMouseNumSamples[0] = 1;
+		mTotalMouseNumSamples[1] = 1;
+		mMouseSmoothedAxis[0] = 0.0f;
+		mMouseSmoothedAxis[1] = 0.0f;
+		mMouseZeroTime[0] = 0.0f;
+		mMouseZeroTime[1] = 0.0f;
+
+		// Raw input
+		initRawInput();
 	}
 
 	Input::~Input()
-	{ }
+	{
+		cleanUpRawInput();
+
+		mCharInputConn.disconnect();
+		mCursorMovedConn.disconnect();
+		mCursorPressedConn.disconnect();
+		mCursorReleasedConn.disconnect();
+		mCursorDoubleClickConn.disconnect();
+		mInputCommandConn.disconnect();
+		mMouseWheelScrolledConn.disconnect();
+	}
 
 	void Input::_update()
 	{
@@ -70,9 +93,7 @@ namespace bs
 
 			UINT32 numAxes = (UINT32)deviceData.axes.size();
 			for (UINT32 i = 0; i < numAxes; i++)
-			{
-				deviceData.axes[i].rel = 0.0f;
-			}
+				deviceData.axes[i] = 0.0f;
 		}
 
 		for (UINT32 i = 0; i < 3; i++)
@@ -86,175 +107,380 @@ namespace bs
 		mPointerDelta = Vector2I::ZERO; // Reset delta in case we don't receive any mouse input this frame
 		mPointerDoubleClicked = false;
 
-		if(mRawInputHandler == nullptr)
+		// Capture raw input
+		if (mMouse != nullptr)
+			mMouse->capture();
+
+		if (mKeyboard != nullptr)
+			mKeyboard->capture();
+
+		for (auto& gamepad : mGamepads)
+			gamepad->capture();
+
+		float rawXValue = 0.0f;
+		float rawYValue = 0.0f;
+
+		// Smooth mouse axes if needed
+		if (mMouseSmoothingEnabled)
 		{
-			LOGERR("Raw input handler not initialized!");
-			return;
+			rawXValue = smoothMouse((float)mMouseSampleAccumulator[0], 0);
+			rawYValue = smoothMouse((float)mMouseSampleAccumulator[1], 1);
 		}
 		else
-			mRawInputHandler->_update();
-
-		if(mOSInputHandler == nullptr)
 		{
-			LOGERR("OS input handler not initialized!");
-			return;
+			rawXValue = (float)mMouseSampleAccumulator[0];
+			rawYValue = (float)mMouseSampleAccumulator[1];
 		}
-		else
-			mOSInputHandler->_update();
+
+		rawXValue *= 0.1f;
+		rawYValue *= 0.1f;
+
+		mMouseSampleAccumulator[0] = 0;
+		mMouseSampleAccumulator[1] = 0;
+
+		axisMoved(0, -rawXValue, (UINT32)InputAxis::MouseX);
+		axisMoved(0, -rawYValue, (UINT32)InputAxis::MouseY);
 	}
 
 	void Input::_triggerCallbacks()
 	{
-		for (auto& event : mQueuedEvents)
+		Vector2I pointerPos;
+		float mouseScroll;
+		OSPointerButtonStates pointerState;
+
+		{
+			Lock lock(mMutex);
+
+			std::swap(mQueuedEvents[0], mQueuedEvents[1]);
+
+			std::swap(mButtonDownEvents[0], mButtonDownEvents[1]);
+			std::swap(mButtonUpEvents[0], mButtonUpEvents[1]);
+
+			std::swap(mPointerPressedEvents[0], mPointerPressedEvents[1]);
+			std::swap(mPointerReleasedEvents[0], mPointerReleasedEvents[1]);
+			std::swap(mPointerDoubleClickEvents[0], mPointerDoubleClickEvents[1]);
+
+			std::swap(mTextInputEvents[0], mTextInputEvents[1]);
+			std::swap(mCommandEvents[0], mCommandEvents[1]);
+
+			pointerPos = mPointerPosition;
+			mouseScroll = mMouseScroll;
+			pointerState = mPointerState;
+
+			mMouseScroll = 0.0f;
+		}
+
+		if(pointerPos != mLastPointerPosition)
+		{
+			PointerEvent event;
+			event.alt = false;
+			event.shift = pointerState.shift;
+			event.control = pointerState.ctrl;
+			event.buttonStates[0] = pointerState.mouseButtons[0];
+			event.buttonStates[1] = pointerState.mouseButtons[1];
+			event.buttonStates[2] = pointerState.mouseButtons[2];
+			event.mouseWheelScrollAmount = mouseScroll;
+
+			event.type = PointerEventType::CursorMoved;
+			event.screenPos = pointerPos;
+
+			onPointerMoved(event);
+
+			if (mLastPositionSet)
+				mPointerDelta = event.screenPos - mLastPointerPosition;
+
+			mLastPointerPosition = event.screenPos;
+			mLastPositionSet = true;
+		}
+
+		for (auto& event : mQueuedEvents[1])
 		{
 			switch (event.type)
 			{
 			case EventType::ButtonDown:
-				onButtonDown(mButtonDownEvents[event.idx]);
+			{
+				const ButtonEvent& eventData = mButtonDownEvents[1][event.idx];
+
+				mDevices[eventData.deviceIdx].keyStates[eventData.buttonCode & 0x0000FFFF] = ButtonState::ToggledOn;
+				onButtonDown(mButtonDownEvents[1][event.idx]);
+			}
 				break;
 			case EventType::ButtonUp:
-				onButtonUp(mButtonUpEvents[event.idx]);
+			{
+				const ButtonEvent& eventData = mButtonUpEvents[1][event.idx];
+
+				while (eventData.deviceIdx >= (UINT32)mDevices.size())
+					mDevices.push_back(DeviceData());
+
+				if (mDevices[eventData.deviceIdx].keyStates[eventData.buttonCode & 0x0000FFFF] == ButtonState::ToggledOn)
+					mDevices[eventData.deviceIdx].keyStates[eventData.buttonCode & 0x0000FFFF] = ButtonState::ToggledOnOff;
+				else
+					mDevices[eventData.deviceIdx].keyStates[eventData.buttonCode & 0x0000FFFF] = ButtonState::ToggledOff;
+
+				onButtonUp(mButtonUpEvents[1][event.idx]);
+			}
 				break;
 			case EventType::PointerDown:
-				onPointerPressed(mPointerPressedEvents[event.idx]);
+			{
+				const PointerEvent& eventData = mPointerPressedEvents[1][event.idx];
+				mPointerButtonStates[(UINT32)eventData.button] = ButtonState::ToggledOn;
+
+				onPointerPressed(eventData);
+			}
 				break;
 			case EventType::PointerUp:
-				onPointerReleased(mPointerReleasedEvents[event.idx]);
+			{
+				const PointerEvent& eventData = mPointerReleasedEvents[1][event.idx];
+
+				if (mPointerButtonStates[(UINT32)eventData.button] == ButtonState::ToggledOn)
+					mPointerButtonStates[(UINT32)eventData.button] = ButtonState::ToggledOnOff;
+				else
+					mPointerButtonStates[(UINT32)eventData.button] = ButtonState::ToggledOff;
+
+				onPointerReleased(eventData);
+			}
 				break;
 			case EventType::PointerDoubleClick:
-				onPointerDoubleClick(mPointerDoubleClickEvents[event.idx]);
-				break;
-			case EventType::PointerMoved:
-				onPointerMoved(mPointerMovedEvents[event.idx]);
+				mPointerDoubleClicked = true;
+				onPointerDoubleClick(mPointerDoubleClickEvents[1][event.idx]);
 				break;
 			case EventType::TextInput:
-				onCharInput(mTextInputEvents[event.idx]);
+				onCharInput(mTextInputEvents[1][event.idx]);
 				break;
 			case EventType::Command:
-				onInputCommand(mCommandEvents[event.idx]);
+				onInputCommand(mCommandEvents[1][event.idx]);
+				break;
+			default:
 				break;
 			}
 		}
 
-		mQueuedEvents.clear();
-		mButtonDownEvents.clear();
-		mButtonUpEvents.clear();
-		mPointerPressedEvents.clear();
-		mPointerReleasedEvents.clear();
-		mPointerDoubleClickEvents.clear();
-		mPointerMovedEvents.clear();
-		mTextInputEvents.clear();
-		mCommandEvents.clear();
+		mQueuedEvents[1].clear();
+		mButtonDownEvents[1].clear();
+		mButtonUpEvents[1].clear();
+		mPointerPressedEvents[1].clear();
+		mPointerReleasedEvents[1].clear();
+		mPointerDoubleClickEvents[1].clear();
+		mTextInputEvents[1].clear();
+		mCommandEvents[1].clear();
 	}
 
 	void Input::inputWindowChanged(RenderWindow& win)
 	{
-		if(mRawInputHandler != nullptr)
-			mRawInputHandler->_inputWindowChanged(win);
+		UINT64 hWnd = 0;
+		win.getCustomAttribute("WINDOW", &hWnd);
+
+		mKeyboard->changeCaptureContext(hWnd);
+		mMouse->changeCaptureContext(hWnd);
+
+		for (auto& gamepad : mGamepads)
+			gamepad->changeCaptureContext(hWnd);
+	}
+
+	void Input::_notifyMouseMoved(INT32 relX, INT32 relY, INT32 relZ)
+	{
+		mMouseSampleAccumulator[0] += relX;
+		mMouseSampleAccumulator[1] += relY;
+
+		mTotalMouseNumSamples[0] += Math::roundToInt(Math::abs((float)relX));
+		mTotalMouseNumSamples[1] += Math::roundToInt(Math::abs((float)relY));
+
+		// Update sample times used for determining sampling rate. But only if something was
+		// actually sampled, and only if this isn't the first non-zero sample.
+		if (mLastMouseUpdateFrame != gTime().getFrameIdx())
+		{
+			if (relX != 0 && !Math::approxEquals(mMouseSmoothedAxis[0], 0.0f))
+				mTotalMouseSamplingTime[0] += gTime().getFrameDelta();
+
+			if (relY != 0 && !Math::approxEquals(mMouseSmoothedAxis[1], 0.0f))
+				mTotalMouseSamplingTime[1] += gTime().getFrameDelta();
+
+			mLastMouseUpdateFrame = gTime().getFrameIdx();
+		}
+
+		axisMoved(0, (float)relZ, (UINT32)InputAxis::MouseZ);
+	}
+
+	void Input::_notifyAxisMoved(UINT32 gamepadIdx, UINT32 axisIdx, INT32 value)
+	{
+		// Move axis values into [-1.0f, 1.0f] range
+		float axisRange = Math::abs((float)Gamepad::MAX_AXIS) + Math::abs((float)Gamepad::MIN_AXIS);
+
+		float axisValue = ((value + Math::abs((float)Gamepad::MIN_AXIS)) / axisRange) * 2.0f - 1.0f;
+		axisMoved(gamepadIdx, axisValue, axisIdx);
+	}
+
+	void Input::_notifyButtonPressed(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp)
+	{
+		buttonDown(deviceIdx, code, timestamp - mTimestampClockOffset);
+	}
 
-		if(mOSInputHandler != nullptr)
-			mOSInputHandler->_inputWindowChanged(win);
+	void Input::_notifyButtonReleased(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp)
+	{
+		buttonUp(deviceIdx, code, timestamp - mTimestampClockOffset);
 	}
 
 	void Input::buttonDown(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp)
 	{
+		Lock lock(mMutex);
+
 		while (deviceIdx >= (UINT32)mDevices.size())
 			mDevices.push_back(DeviceData());
 
-		mDevices[deviceIdx].keyStates[code & 0x0000FFFF] = ButtonState::ToggledOn;
-
 		ButtonEvent btnEvent;
 		btnEvent.buttonCode = code;
 		btnEvent.timestamp = timestamp;
 		btnEvent.deviceIdx = deviceIdx;
 
-		mQueuedEvents.push_back(QueuedEvent(EventType::ButtonDown, (UINT32)mButtonDownEvents.size()));
-		mButtonDownEvents.push_back(btnEvent);
+		mQueuedEvents[0].push_back(QueuedEvent(EventType::ButtonDown, (UINT32)mButtonDownEvents[0].size()));
+		mButtonDownEvents[0].push_back(btnEvent);
 	}
 
 	void Input::buttonUp(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp)
 	{
-		while (deviceIdx >= (UINT32)mDevices.size())
-			mDevices.push_back(DeviceData());
-
-		if (mDevices[deviceIdx].keyStates[code & 0x0000FFFF] == ButtonState::ToggledOn)
-			mDevices[deviceIdx].keyStates[code & 0x0000FFFF] = ButtonState::ToggledOnOff;
-		else
-			mDevices[deviceIdx].keyStates[code & 0x0000FFFF] = ButtonState::ToggledOff;
+		Lock lock(mMutex);
 
 		ButtonEvent btnEvent;
 		btnEvent.buttonCode = code;
 		btnEvent.timestamp = timestamp;
 		btnEvent.deviceIdx = deviceIdx;
 
-		mQueuedEvents.push_back(QueuedEvent(EventType::ButtonUp, (UINT32)mButtonUpEvents.size()));
-		mButtonUpEvents.push_back(btnEvent);
+		mQueuedEvents[0].push_back(QueuedEvent(EventType::ButtonUp, (UINT32)mButtonUpEvents[0].size()));
+		mButtonUpEvents[0].push_back(btnEvent);
 	}
 
-	void Input::axisMoved(UINT32 deviceIdx, const RawAxisState& state, UINT32 axis)
+	void Input::axisMoved(UINT32 deviceIdx, float value, UINT32 axis)
 	{
+		// Note: This method must only ever be called from the main thread, as we don't lock access to axis data
 		while (deviceIdx >= (UINT32)mDevices.size())
 			mDevices.push_back(DeviceData());
 
-		Vector<RawAxisState>& axes = mDevices[deviceIdx].axes;
+		Vector<float>& axes = mDevices[deviceIdx].axes;
 		while (axis >= (UINT32)axes.size())
-			axes.push_back(RawAxisState());
+			axes.push_back(0.0f);
 
-		mDevices[deviceIdx].axes[axis] = state;
+		mDevices[deviceIdx].axes[axis] = value;
 	}
 
-	void Input::cursorMoved(const PointerEvent& event)
+	void Input::cursorMoved(const Vector2I& cursorPos, const OSPointerButtonStates& btnStates)
 	{
-		mQueuedEvents.push_back(QueuedEvent(EventType::PointerMoved, (UINT32)mPointerMovedEvents.size()));
-		mPointerMovedEvents.push_back(event);
+		Lock lock(mMutex);
 
-		if (mLastPositionSet)
-			mPointerDelta = event.screenPos - mPointerPosition;
-
-		mPointerPosition = event.screenPos;
-		mLastPositionSet = true;
+		mPointerPosition = cursorPos;
+		mPointerState = btnStates;
 	}
 
-	void Input::cursorPressed(const PointerEvent& event)
+	void Input::cursorPressed(const Vector2I& cursorPos, OSMouseButton button, const OSPointerButtonStates& btnStates)
 	{
-		mPointerButtonStates[(UINT32)event.button] = ButtonState::ToggledOn;
+		Lock lock(mMutex);
+
+		PointerEvent event;
+		event.alt = false;
+		event.shift = btnStates.shift;
+		event.control = btnStates.ctrl;
+		event.buttonStates[0] = btnStates.mouseButtons[0];
+		event.buttonStates[1] = btnStates.mouseButtons[1];
+		event.buttonStates[2] = btnStates.mouseButtons[2];
+		
+		switch(button)
+		{
+		case OSMouseButton::Left:
+			event.button = PointerEventButton::Left;
+			break;
+		case OSMouseButton::Middle:
+			event.button = PointerEventButton::Middle;
+			break;
+		case OSMouseButton::Right:
+			event.button = PointerEventButton::Right;
+			break;
+		default:
+			break;
+		}
+		
+		event.screenPos = cursorPos;
+		event.type = PointerEventType::ButtonPressed;
 
-		mQueuedEvents.push_back(QueuedEvent(EventType::PointerDown, (UINT32)mPointerPressedEvents.size()));
-		mPointerPressedEvents.push_back(event);
+		mQueuedEvents[0].push_back(QueuedEvent(EventType::PointerDown, (UINT32)mPointerPressedEvents[0].size()));
+		mPointerPressedEvents[0].push_back(event);
 	}
 
-	void Input::cursorReleased(const PointerEvent& event)
+	void Input::cursorReleased(const Vector2I& cursorPos, OSMouseButton button, const OSPointerButtonStates& btnStates)
 	{
-		if (mPointerButtonStates[(UINT32)event.button] == ButtonState::ToggledOn)
-			mPointerButtonStates[(UINT32)event.button] = ButtonState::ToggledOnOff;
-		else
-			mPointerButtonStates[(UINT32)event.button] = ButtonState::ToggledOff;
+		Lock lock(mMutex);
+
+		PointerEvent event;
+		event.alt = false;
+		event.shift = btnStates.shift;
+		event.control = btnStates.ctrl;
+		event.buttonStates[0] = btnStates.mouseButtons[0];
+		event.buttonStates[1] = btnStates.mouseButtons[1];
+		event.buttonStates[2] = btnStates.mouseButtons[2];
+		
+		switch(button)
+		{
+		case OSMouseButton::Left:
+			event.button = PointerEventButton::Left;
+			break;
+		case OSMouseButton::Middle:
+			event.button = PointerEventButton::Middle;
+			break;
+		case OSMouseButton::Right:
+			event.button = PointerEventButton::Right;
+			break;
+		default:
+			break;
+		}
+		
+		event.screenPos = cursorPos;
+		event.type = PointerEventType::ButtonReleased;
 
-		mQueuedEvents.push_back(QueuedEvent(EventType::PointerUp, (UINT32)mPointerReleasedEvents.size()));
-		mPointerReleasedEvents.push_back(event);
+		mQueuedEvents[0].push_back(QueuedEvent(EventType::PointerUp, (UINT32)mPointerReleasedEvents[0].size()));
+		mPointerReleasedEvents[0].push_back(event);
 	}
 
-	void Input::cursorDoubleClick(const PointerEvent& event)
+	void Input::cursorDoubleClick(const Vector2I& cursorPos, const OSPointerButtonStates& btnStates)
 	{
-		mPointerDoubleClicked = true;
-
-		mQueuedEvents.push_back(QueuedEvent(EventType::PointerDoubleClick, (UINT32)mPointerDoubleClickEvents.size()));
-		mPointerDoubleClickEvents.push_back(event);
+		Lock lock(mMutex);
+
+		PointerEvent event;
+		event.alt = false;
+		event.shift = btnStates.shift;
+		event.control = btnStates.ctrl;
+		event.buttonStates[0] = btnStates.mouseButtons[0];
+		event.buttonStates[1] = btnStates.mouseButtons[1];
+		event.buttonStates[2] = btnStates.mouseButtons[2];
+		event.button = PointerEventButton::Left;
+		event.screenPos = cursorPos;
+		event.type = PointerEventType::DoubleClick;
+
+		mQueuedEvents[0].push_back(QueuedEvent(EventType::PointerDoubleClick, (UINT32)mPointerDoubleClickEvents[0].size()));
+		mPointerDoubleClickEvents[0].push_back(event);
 	}
 
 	void Input::inputCommandEntered(InputCommandType commandType)
 	{
-		mQueuedEvents.push_back(QueuedEvent(EventType::Command, (UINT32)mCommandEvents.size()));
-		mCommandEvents.push_back(commandType);
+		Lock lock(mMutex);
+
+		mQueuedEvents[0].push_back(QueuedEvent(EventType::Command, (UINT32)mCommandEvents[0].size()));
+		mCommandEvents[0].push_back(commandType);
+	}
+
+	void Input::mouseWheelScrolled(float scrollPos)
+	{
+		Lock lock(mMutex);
+
+		mMouseScroll = scrollPos;
 	}
 
 	void Input::charInput(UINT32 chr)
 	{
+		Lock lock(mMutex);
+
 		TextInputEvent textInputEvent;
 		textInputEvent.textChar = chr;
 
-		mQueuedEvents.push_back(QueuedEvent(EventType::TextInput, (UINT32)mTextInputEvents.size()));
-		mTextInputEvents.push_back(textInputEvent);
+		mQueuedEvents[0].push_back(QueuedEvent(EventType::TextInput, (UINT32)mTextInputEvents[0].size()));
+		mTextInputEvents[0].push_back(textInputEvent);
 	}
 
 	float Input::getAxisValue(UINT32 type, UINT32 deviceIdx) const
@@ -262,11 +488,11 @@ namespace bs
 		if (deviceIdx >= (UINT32)mDevices.size())
 			return 0.0f;
 
-		const Vector<RawAxisState>& axes = mDevices[deviceIdx].axes;
+		const Vector<float>& axes = mDevices[deviceIdx].axes;
 		if (type >= (UINT32)axes.size())
 			return 0.0f;
 
-		return axes[type].rel;
+		return axes[type];
 	}
 
 	bool Input::isButtonHeld(ButtonCode button, UINT32 deviceIdx) const
@@ -326,9 +552,73 @@ namespace bs
 		return mPointerPosition;
 	}
 
+	String Input::getDeviceName(InputDevice type, UINT32 idx)
+	{
+		switch(type)
+		{
+		case InputDevice::Keyboard: 
+			if (mKeyboard != nullptr && idx == 0)
+				return mKeyboard->getName();
+
+			return StringUtil::BLANK;
+		case InputDevice::Mouse:
+			if (mMouse != nullptr && idx == 0)
+				return mMouse->getName();
+
+			return StringUtil::BLANK;
+		case InputDevice::Gamepad: 
+			if (idx < (UINT32)mGamepads.size())
+				return mGamepads[idx]->getName();
+			
+			return StringUtil::BLANK;
+		default:
+			return StringUtil::BLANK;
+		}
+	}
+
 	void Input::setMouseSmoothing(bool enable)
 	{
-		mRawInputHandler->setMouseSmoothing(enable);
+		mMouseSmoothingEnabled = enable;
+	}
+
+	float Input::smoothMouse(float value, UINT32 idx)
+	{
+		UINT32 sampleCount = 1;
+
+		float deltaTime = gTime().getFrameDelta();
+		if (deltaTime < 0.25f)
+		{
+			float secondsPerSample = mTotalMouseSamplingTime[idx] / mTotalMouseNumSamples[idx];
+
+			if (value == 0.0f)
+			{
+				mMouseZeroTime[idx] += deltaTime;
+				if (mMouseZeroTime[idx] < secondsPerSample)
+					value = mMouseSmoothedAxis[idx] * deltaTime / secondsPerSample;
+				else
+					mMouseSmoothedAxis[idx] = 0;
+			}
+			else
+			{
+				mMouseZeroTime[idx] = 0;
+				if (mMouseSmoothedAxis[idx] != 0)
+				{
+					if (deltaTime < secondsPerSample * (sampleCount + 1))
+						value = value * deltaTime / (secondsPerSample * sampleCount);
+					else
+						sampleCount = Math::roundToInt(deltaTime / secondsPerSample);
+				}
+
+				mMouseSmoothedAxis[idx] = value / sampleCount;
+			}
+		}
+		else
+		{
+			mMouseSmoothedAxis[idx] = 0.0f;
+			mMouseZeroTime[idx] = 0.0f;
+		}
+
+		return value;
 	}
 
 	Input& gInput()

+ 137 - 31
Source/BansheeCore/Input/BsInput.h

@@ -4,12 +4,16 @@
 
 #include "BsCorePrerequisites.h"
 #include "Utility/BsModule.h"
-#include "Input/BsOSInputHandler.h"
-#include "Input/BsRawInputHandler.h"
+#include "Platform/BsPlatform.h"
 #include "Input/BsInputFwd.h"
 
 namespace bs
 {
+	class Mouse;
+	class Keyboard;
+	class Gamepad;
+	struct InputPrivateData;
+
 	/** @addtogroup Input
 	 *  @{
 	 */
@@ -35,7 +39,7 @@ namespace bs
 		{
 			DeviceData();
 
-			Vector<RawAxisState> axes;
+			Vector<float> axes;
 			ButtonState keyStates[BC_Count];
 		};
 
@@ -126,6 +130,12 @@ namespace bs
 		/** Enables or disables mouse smoothing. Smoothing makes the changes to mouse axes more gradual. */
 		void setMouseSmoothing(bool enabled);
 
+		/** Returns the number of detected devices of the specified type. */
+		UINT32 getDeviceCount(InputDevice device) const;
+
+		/** Returns the name of a specific input device. Returns empty string if the device doesn't exist. */
+		String getDeviceName(InputDevice type, UINT32 idx);
+
 		/** Triggered whenever a button is first pressed. */
 		Event<void(const ButtonEvent&)> onButtonDown;
 
@@ -165,61 +175,157 @@ namespace bs
 		/** Triggers any queued input event callbacks. */
 		void _triggerCallbacks();
 
+		/** Returns internal, platform specific privata data. */
+		InputPrivateData* _getPrivateData() const { return mPlatformData; }
+
+		/** Returns a handle to the window that is currently receiving input. */
+		UINT64 _getWindowHandle() const { return mWindowHandle; }
+
+		/** Called by Mouse when mouse movement is detected. */
+		void _notifyMouseMoved(INT32 relX, INT32 relY, INT32 relZ);
+
+		/** Called by any of the raw input devices when analog axis movement is detected. */
+		void _notifyAxisMoved(UINT32 gamepadIdx, UINT32 axisIdx, INT32 value);
+
+		/** Called by any of the raw input devices when a button is pressed. */
+		void _notifyButtonPressed(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp);
+
+		/** Called by any of the raw input devices when a button is released. */
+		void _notifyButtonReleased(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp);
+
 		/** @} */
 
 	private:
+		/** Performs platform specific raw input system initialization. */
+		void initRawInput();
+
+		/** Performs platform specific raw input system cleanup. */
+		void cleanUpRawInput();
+		
+		/**
+		 * Smooths the input mouse axis value. Smoothing makes the changes to the axis more gradual depending on previous
+		 * values.
+		 *
+		 * @param[in]	value	Value to smooth.
+		 * @param[in]	idx		Index of the mouse axis to smooth, 0 - horizontal, 1 - vertical.
+		 * @return				Smoothed value.
+		 */
+		float smoothMouse(float value, UINT32 idx);
+
 		/**	Triggered by input handler when a button is pressed. */
 		void buttonDown(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp);
 
 		/**	Triggered by input handler when a button is released. */
 		void buttonUp(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp);
 
-		/**	Triggered by input handler when a single character is input. */
-		void charInput(UINT32 chr);
-
 		/**	Triggered by input handler when a mouse/joystick axis is moved. */
-		void axisMoved(UINT32 deviceIdx, const RawAxisState& state, UINT32 axis);
+		void axisMoved(UINT32 deviceIdx, float value, UINT32 axis);
+
+		/**
+		 * Called from the message loop to notify user has entered a character.
+		 * 			
+		 * @see		onCharInput
+		 */
+		void charInput(UINT32 character);
 
-		/**	Cursor movement as OS reports it. Used for screen cursor position. */
-		void cursorMoved(const PointerEvent& event);
+		/**
+		 * Called from the message loop to notify user has moved the cursor.
+		 * 			
+		 * @see		onCursorMoved
+		 */
+		void cursorMoved(const Vector2I& cursorPos, const OSPointerButtonStates& btnStates);
 
-		/**	Cursor button presses as OS reports it. */
-		void cursorPressed(const PointerEvent& event);
+		/**
+		 * Called from the message loop to notify user has pressed a mouse button.
+		 * 			
+		 * @see		onCursorPressed
+		 */
+		void cursorPressed(const Vector2I& cursorPos, OSMouseButton button, const OSPointerButtonStates& btnStates);
 
-		/**	Cursor button releases as OS reports it. */
-		void cursorReleased(const PointerEvent& event);
-		
-		/**	Cursor button releases as OS reports it. */
-		void cursorDoubleClick(const PointerEvent& event);
+		/**
+		 * Called from the message loop to notify user has released a mouse button.
+		 * 			
+		 * @see		onCursorReleased
+		 */
+		void cursorReleased(const Vector2I& cursorPos, OSMouseButton button, const OSPointerButtonStates& btnStates);
+
+		/**
+		 * Called from the message loop to notify user has double-clicked a mouse button.
+		 * 
+		 * @see		onDoubleClick
+		 */
+		void cursorDoubleClick(const Vector2I& cursorPos, const OSPointerButtonStates& btnStates);
 
-		/** Input commands as OS reports them. */
+		/**
+		 * Called from the message loop to notify user has entered an input command.
+		 * 			
+		 * @see		onInputCommand
+		 */
 		void inputCommandEntered(InputCommandType commandType);
 
+		/**
+		 * Called from the message loop to notify user has scrolled the mouse wheel.
+		 * 			
+		 * @see		onMouseWheelScrolled
+		 */
+		void mouseWheelScrolled(float scrollPos);
+
 		/** Called when window in focus changes, as reported by the OS. */
 		void inputWindowChanged(RenderWindow& win);
 
 	private:
-		SPtr<RawInputHandler> mRawInputHandler;
-		SPtr<OSInputHandler> mOSInputHandler;
+		Mutex mMutex;
 
 		Vector<DeviceData> mDevices;
-		Vector2I mPointerPosition;
+		Vector2I mLastPointerPosition;
 		Vector2I mPointerDelta;
 		ButtonState mPointerButtonStates[3];
 		bool mPointerDoubleClicked;
 		bool mLastPositionSet;
 
-		Vector<QueuedEvent> mQueuedEvents;
-
-		Vector<TextInputEvent> mTextInputEvents;
-		Vector<InputCommandType> mCommandEvents;
-		Vector<PointerEvent> mPointerDoubleClickEvents;
-		Vector<PointerEvent> mPointerReleasedEvents;
-		Vector<PointerEvent> mPointerPressedEvents;
-		Vector<PointerEvent> mPointerMovedEvents;
-
-		Vector<ButtonEvent> mButtonDownEvents;
-		Vector<ButtonEvent> mButtonUpEvents;
+		// Thread safe
+		Vector2I mPointerPosition;
+		float mMouseScroll;
+		OSPointerButtonStates mPointerState;
+
+		Vector<QueuedEvent> mQueuedEvents[2];
+
+		Vector<TextInputEvent> mTextInputEvents[2];
+		Vector<InputCommandType> mCommandEvents[2];
+		Vector<PointerEvent> mPointerDoubleClickEvents[2];
+		Vector<PointerEvent> mPointerReleasedEvents[2];
+		Vector<PointerEvent> mPointerPressedEvents[2];
+
+		Vector<ButtonEvent> mButtonDownEvents[2];
+		Vector<ButtonEvent> mButtonUpEvents[2];
+
+		// OS input events
+		HEvent mCharInputConn;
+		HEvent mCursorMovedConn;
+		HEvent mCursorPressedConn;
+		HEvent mCursorReleasedConn;
+		HEvent mCursorDoubleClickConn;
+		HEvent mInputCommandConn;
+		HEvent mMouseWheelScrolledConn;
+
+		// Raw input
+		bool mMouseSmoothingEnabled;
+		UINT64 mWindowHandle;
+
+		Mouse* mMouse;
+		Keyboard* mKeyboard;
+		Vector<Gamepad*> mGamepads;
+
+		float mTotalMouseSamplingTime[2];
+		UINT32 mTotalMouseNumSamples[2];
+		float mMouseZeroTime[2];
+		INT32 mMouseSampleAccumulator[2];
+		float mMouseSmoothedAxis[2];
+		UINT64 mLastMouseUpdateFrame;
+
+		UINT64 mTimestampClockOffset;
+
+		InputPrivateData* mPlatformData;
 
 		/************************************************************************/
 		/* 								STATICS		                      		*/

+ 5 - 5
Source/BansheeCore/Input/BsKeyboard.h

@@ -6,29 +6,29 @@
 
 namespace bs
 {
-	/** Represents a single hardware keyboard. Used by the RawInputHandler to report raw keyboard input events. */
+	/** Represents a single hardware keyboard. Used by the Input to report raw keyboard input events. */
 	class BS_CORE_EXPORT Keyboard
 	{
 	public:
 		struct Pimpl;
 
-		Keyboard(const String& name, RawInputHandler* owner);
+		Keyboard(const String& name, Input* owner);
 		~Keyboard();
 
 		/** Returns the name of the device. */
 		String getName() const { return mName; }
 
-		/** Captures the input since the last call and triggers the events on the parent RawInputHandler. */
+		/** Captures the input since the last call and triggers the events on the parent Input. */
 		void capture();
 
 	private:
-		friend class RawInputHandler;
+		friend class Input;
 
 		/** Changes the capture context. Should be called when focus is moved to a new window. */
 		void changeCaptureContext(UINT64 windowHandle);
 
 		String mName;
-		RawInputHandler* mOwner;
+		Input* mOwner;
 
 		Pimpl* m;
 	};

+ 5 - 5
Source/BansheeCore/Input/BsMouse.h

@@ -6,29 +6,29 @@
 
 namespace bs
 {
-	/** Represents a single hardware mouse. Used by the RawInputHandler to report raw mouse input events. */
+	/** Represents a single hardware mouse. Used by the Input to report raw mouse input events. */
 	class BS_CORE_EXPORT Mouse
 	{
 	public:
 		struct Pimpl;
 
-		Mouse(const String& name, RawInputHandler* owner);
+		Mouse(const String& name, Input* owner);
 		~Mouse();
 
 		/** Returns the name of the device. */
 		String getName() const { return mName; }
 
-		/** Captures the input since the last call and triggers the events on the parent RawInputHandler. */
+		/** Captures the input since the last call and triggers the events on the parent Input. */
 		void capture();
 
 	private:
-		friend class RawInputHandler;
+		friend class Input;
 
 		/** Changes the capture context. Should be called when focus is moved to a new window. */
 		void changeCaptureContext(UINT64 windowHandle);
 
 		String mName;
-		RawInputHandler* mOwner;
+		Input* mOwner;
 
 		Pimpl* m;
 	};

+ 0 - 247
Source/BansheeCore/Input/BsOSInputHandler.cpp

@@ -1,247 +0,0 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "Input/BsOSInputHandler.h"
-#include "Platform/BsPlatform.h"
-#include "Input/BsInput.h"
-#include "Math/BsMath.h"
-
-using namespace std::placeholders;
-
-namespace bs
-{
-	OSInputHandler::OSInputHandler()
-		:mLastCursorPosSet(false), mMouseScroll(0.0f)
-	{
-		mCharInputConn = Platform::onCharInput.connect(std::bind(&OSInputHandler::charInput, this, _1));
-		mCursorMovedConn = Platform::onCursorMoved.connect(std::bind(&OSInputHandler::cursorMoved, this, _1, _2));
-		mCursorPressedConn = Platform::onCursorButtonPressed.connect(std::bind(&OSInputHandler::cursorPressed, this, _1, _2, _3));
-		mCursorReleasedConn = Platform::onCursorButtonReleased.connect(std::bind(&OSInputHandler::cursorReleased, this, _1, _2, _3));
-		mCursorDoubleClickConn = Platform::onCursorDoubleClick.connect(std::bind(&OSInputHandler::cursorDoubleClick, this, _1, _2));
-		mInputCommandConn = Platform::onInputCommand.connect(std::bind(&OSInputHandler::inputCommandEntered, this, _1));
-
-		mMouseWheelScrolledConn  = Platform::onMouseWheelScrolled.connect(std::bind(&OSInputHandler::mouseWheelScrolled, this, _1));
-	}
-
-	OSInputHandler::~OSInputHandler()
-	{
-		mCharInputConn.disconnect();
-		mCursorMovedConn.disconnect();
-		mCursorPressedConn.disconnect();
-		mCursorReleasedConn.disconnect();
-		mCursorDoubleClickConn.disconnect();
-		mInputCommandConn.disconnect();
-		mMouseWheelScrolledConn.disconnect();
-	}
-
-	void OSInputHandler::_update()
-	{
-		WString inputString;
-		Vector2I mousePosition;
-		float mouseScroll;
-		OSPointerButtonStates mouseMoveBtnState;
-		Queue<ButtonStateChange> buttonStates;
-		Queue<DoubleClick> doubleClicks;
-		Queue<InputCommandType> inputCommands;
-
-		{
-			Lock lock(mOSInputMutex);
-			inputString = mInputString;
-			mInputString.clear();
-
-			mousePosition = mCursorPosition;
-			mouseScroll = mMouseScroll;
-			mMouseScroll = 0.0f;
-
-			mouseMoveBtnState = mMouseMoveBtnState;
-
-			buttonStates = mButtonStates;
-			mButtonStates = Queue<ButtonStateChange>();
-
-			inputCommands = mInputCommands;
-			mInputCommands = Queue<InputCommandType>();
-
-			doubleClicks = mDoubleClicks;
-			mDoubleClicks = Queue<DoubleClick>();
-		}
-
-		if(mousePosition != mLastCursorPos || (Math::abs(mouseScroll) > 0.00001f))
-		{
-			if(!onCursorMoved.empty())
-			{
-				PointerEvent event;
-				event.alt = false;
-				event.shift = mouseMoveBtnState.shift;
-				event.control = mouseMoveBtnState.ctrl;
-				event.buttonStates[0] = mouseMoveBtnState.mouseButtons[0];
-				event.buttonStates[1] = mouseMoveBtnState.mouseButtons[1];
-				event.buttonStates[2] = mouseMoveBtnState.mouseButtons[2];
-				event.mouseWheelScrollAmount = mouseScroll;
-
-				event.type = PointerEventType::CursorMoved;
-				event.screenPos = mousePosition;
-
-				if (mLastCursorPosSet)
-					event.delta = mousePosition - mLastCursorPos;
-
-				onCursorMoved(event);
-			}
-
-			mLastCursorPos = mousePosition;
-			mLastCursorPosSet = true;
-		}
-
-		while(!buttonStates.empty())
-		{
-			ButtonStateChange& btnState = buttonStates.front();
-
-			PointerEvent event;
-			event.alt = false;
-			event.shift = btnState.btnStates.shift;
-			event.control = btnState.btnStates.ctrl;
-			event.buttonStates[0] = btnState.btnStates.mouseButtons[0];
-			event.buttonStates[1] = btnState.btnStates.mouseButtons[1];
-			event.buttonStates[2] = btnState.btnStates.mouseButtons[2];
-			
-			switch(btnState.button)
-			{
-			case OSMouseButton::Left:
-				event.button = PointerEventButton::Left;
-				break;
-			case OSMouseButton::Middle:
-				event.button = PointerEventButton::Middle;
-				break;
-			case OSMouseButton::Right:
-				event.button = PointerEventButton::Right;
-				break;
-			default:
-				break;
-			}
-			
-			event.screenPos = btnState.cursorPos;
-
-			if(btnState.pressed)
-			{
-				event.type = PointerEventType::ButtonPressed;
-
-				if(!onCursorPressed.empty())
-					onCursorPressed(event);
-			}
-			else
-			{
-				event.type = PointerEventType::ButtonReleased;
-
-				if(!onCursorReleased.empty())
-					onCursorReleased(event);
-			}
-
-			buttonStates.pop();
-		}
-
-		while(!doubleClicks.empty())
-		{
-			if(!onDoubleClick.empty())
-			{
-				DoubleClick& btnState = doubleClicks.front();
-
-				PointerEvent event;
-				event.alt = false;
-				event.shift = btnState.btnStates.shift;
-				event.control = btnState.btnStates.ctrl;
-				event.buttonStates[0] = btnState.btnStates.mouseButtons[0];
-				event.buttonStates[1] = btnState.btnStates.mouseButtons[1];
-				event.buttonStates[2] = btnState.btnStates.mouseButtons[2];
-				event.button = PointerEventButton::Left;
-				event.screenPos = btnState.cursorPos;
-				event.type = PointerEventType::DoubleClick;
-
-				onDoubleClick(event);
-			}
-
-			doubleClicks.pop();
-		}
-
-		while(!inputCommands.empty())
-		{
-			if(!onInputCommand.empty())
-				onInputCommand(inputCommands.front());
-
-			inputCommands.pop();
-		}
-
-		if(!onCharInput.empty())
-		{
-			for(auto& curChar : inputString)
-			{
-				onCharInput((UINT32)curChar);
-			}
-		}
-	}
-
-	void OSInputHandler::charInput(UINT32 character)
-	{
-		Lock lock(mOSInputMutex);
-
-		mInputString += character;
-	}
-
-	void OSInputHandler::cursorMoved(const Vector2I& cursorPos, const OSPointerButtonStates& btnStates)
-	{
-		Lock lock(mOSInputMutex);
-
-		mCursorPosition = cursorPos;
-		mMouseMoveBtnState = btnStates;
-	}
-
-	void OSInputHandler::cursorPressed(const Vector2I& cursorPos, 
-		OSMouseButton button, const OSPointerButtonStates& btnStates)
-	{
-		Lock lock(mOSInputMutex);
-
-		mButtonStates.push(ButtonStateChange());
-		ButtonStateChange& btnState = mButtonStates.back();
-
-		btnState.cursorPos = cursorPos;
-		btnState.button = button;
-		btnState.pressed = true;
-		btnState.btnStates = btnStates;
-	}
-
-	void OSInputHandler::cursorReleased(const Vector2I& cursorPos, 
-		OSMouseButton button, const OSPointerButtonStates& btnStates)
-	{
-		Lock lock(mOSInputMutex);
-
-		mButtonStates.push(ButtonStateChange());
-		ButtonStateChange& btnState = mButtonStates.back();
-
-		btnState.cursorPos = cursorPos;
-		btnState.button = button;
-		btnState.pressed = false;
-		btnState.btnStates = btnStates;
-	}
-
-	void OSInputHandler::cursorDoubleClick(const Vector2I& cursorPos, const OSPointerButtonStates& btnStates)
-	{
-		Lock lock(mOSInputMutex);
-
-		mDoubleClicks.push(DoubleClick());
-		DoubleClick& btnState = mDoubleClicks.back();
-
-		btnState.cursorPos = cursorPos;
-		btnState.btnStates = btnStates;
-	}
-
-	void OSInputHandler::inputCommandEntered(InputCommandType commandType)
-	{
-		Lock lock(mOSInputMutex);
-
-		mInputCommands.push(commandType);
-	}
-
-	void OSInputHandler::mouseWheelScrolled(float scrollPos)
-	{
-		Lock lock(mOSInputMutex);
-
-		mMouseScroll = scrollPos;
-	}
-}

+ 0 - 155
Source/BansheeCore/Input/BsOSInputHandler.h

@@ -1,155 +0,0 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsCorePrerequisites.h"
-#include "Platform/BsPlatform.h"
-#include "Utility/BsEvent.h"
-#include "Math/BsVector2I.h"
-
-namespace bs
-{
-	/** @addtogroup Input-Internal
-	 *  @{
-	 */
-
-	/**
-	 * Represents a specific way of acquiring OS input. Input class (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 BS_CORE_EXPORT OSInputHandler
-	{
-		/**	Contains information regarding a button state change event. */
-		struct ButtonStateChange
-		{
-			Vector2I cursorPos;
-			OSPointerButtonStates btnStates;
-			OSMouseButton button;
-			bool pressed;
-		};
-
-		/**	Contains information regarding a double click event. */
-		struct DoubleClick
-		{
-			Vector2I cursorPos;
-			OSPointerButtonStates btnStates;
-		};
-
-	public:
-		OSInputHandler();
-		virtual ~OSInputHandler();
-
-		/** Called once per frame. Capture input here if needed. */
-		virtual void _update();
-
-		/**
-		 * Called whenever the active window changes.
-		 *
-		 * @param[in]	win	Newly active window.
-		 */
-		virtual void _inputWindowChanged(const RenderWindow& win) { }
-
-		/**
-		 * Triggers when user inputs a character. The character might be a result of pressing multiple keys, so character 
-		 * input will not necessarily correspond with button presses. Provide character code of the input character.
-		 */
-		Event<void(UINT32)> onCharInput;
-
-		/**
-		 * Triggers whenever user scrolls the mouse wheel. Returns the screen position of the mouse cursor and delta amount 
-		 * of mouse scroll (can be negative or positive).
-		 */
-		Event<void(const Vector2I&, float)> onMouseWheelScrolled;
-
-		/** Triggers whenever user moves the mouse cursor. */
-		Event<void(const PointerEvent&)> onCursorMoved;
-
-		/**	Triggers whenever user presses one of the mouse buttons. */
-		Event<void(const PointerEvent&)> onCursorPressed;
-
-		/**	Triggers whenever user releases one of the mouse buttons. */
-		Event<void(const PointerEvent&)> onCursorReleased;
-
-		/**	Triggers when user clicks a mouse button quickly twice in a row. */
-		Event<void(const PointerEvent&)> onDoubleClick;
-
-		/**	Triggers when user inputa a special input command, like commands user for manipulating text input. */
-		Event<void(InputCommandType)> onInputCommand;
-
-	private:
-		Mutex mOSInputMutex;
-		Vector2I mLastCursorPos;
-		Vector2I mCursorPosition;
-		Vector2I mDelta;
-		bool mLastCursorPosSet;
-		float mMouseScroll;
-		WString mInputString;
-		Queue<ButtonStateChange> mButtonStates;
-		Queue<DoubleClick> mDoubleClicks;
-		Queue<InputCommandType> mInputCommands;
-		OSPointerButtonStates mMouseMoveBtnState;
-
-		HEvent mCharInputConn;
-		HEvent mCursorMovedConn;
-		HEvent mCursorPressedConn;
-		HEvent mCursorReleasedConn;
-		HEvent mCursorDoubleClickConn;
-		HEvent mInputCommandConn;
-		HEvent mMouseWheelScrolledConn;
-
-		/**
-		 * Called from the message loop to notify user has entered a character.
-		 * 			
-		 * @see		onCharInput
-		 */
-		void charInput(UINT32 character);
-
-		/**
-		 * Called from the message loop to notify user has moved the cursor.
-		 * 			
-		 * @see		onCursorMoved
-		 */
-		void cursorMoved(const Vector2I& cursorPos, const OSPointerButtonStates& btnStates);
-
-		/**
-		 * Called from the message loop to notify user has pressed a mouse button.
-		 * 			
-		 * @see		onCursorPressed
-		 */
-		void cursorPressed(const Vector2I& cursorPos, OSMouseButton button, const OSPointerButtonStates& btnStates);
-
-		/**
-		 * Called from the message loop to notify user has released a mouse button.
-		 * 			
-		 * @see		onCursorReleased
-		 */
-		void cursorReleased(const Vector2I& cursorPos, OSMouseButton button, const OSPointerButtonStates& btnStates);
-
-		/**
-		 * Called from the message loop to notify user has double-clicked a mouse button.
-		 * 
-		 * @see		onDoubleClick
-		 */
-		void cursorDoubleClick(const Vector2I& cursorPos, const OSPointerButtonStates& btnStates);
-
-		/**
-		 * Called from the message loop to notify user has entered an input command.
-		 * 			
-		 * @see		onInputCommand
-		 */
-		void inputCommandEntered(InputCommandType commandType);
-
-		/**
-		 * Called from the message loop to notify user has scrolled the mouse wheel.
-		 * 			
-		 * @see		onMouseWheelScrolled
-		 */
-		void mouseWheelScrolled(float scrollPos);
-	};
-
-	/** @} */
-}

+ 0 - 187
Source/BansheeCore/Input/BsRawInputHandler.cpp

@@ -1,187 +0,0 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "Input/BsRawInputHandler.h"
-#include "Input/BsMouse.h"
-#include "Input/BsKeyboard.h"
-#include "Input/BsGamepad.h"
-#include "Utility/BsTime.h"
-#include "RenderAPI/BsRenderWindow.h"
-#include "Math/BsMath.h"
-
-namespace bs
-{
-	RawInputHandler::RawInputHandler(UINT64 windowHandle)
-		: mMouseSmoothingEnabled(false), mWindowHandle(windowHandle), mMouse(nullptr), mKeyboard(nullptr)
-	{
-		mMouseSampleAccumulator[0] = 0;
-		mMouseSampleAccumulator[1] = 0;
-		mTotalMouseSamplingTime[0] = 1.0f / 125.0f; // Use 125Hz as initial pooling rate for mice
-		mTotalMouseSamplingTime[1] = 1.0f / 125.0f;
-		mTotalMouseNumSamples[0] = 1;
-		mTotalMouseNumSamples[1] = 1;
-		mMouseSmoothedAxis[0] = 0.0f;
-		mMouseSmoothedAxis[1] = 0.0f;
-		mMouseZeroTime[0] = 0.0f;
-		mMouseZeroTime[1] = 0.0f;
-
-		initialize();
-
-		mTimestampClockOffset = gTime().getStartTimeMs();
-	}
-
-	RawInputHandler::~RawInputHandler()
-	{
-		if (mMouse != nullptr)
-			bs_delete(mMouse);
-
-		if (mKeyboard != nullptr)
-			bs_delete(mKeyboard);
-
-		for (auto& gamepad : mGamepads)
-			bs_delete(gamepad);
-
-		cleanUp();
-	}
-
-	void RawInputHandler::_update()
-	{
-		if (mMouse != nullptr)
-			mMouse->capture();
-
-		if (mKeyboard != nullptr)
-			mKeyboard->capture();
-
-		for (auto& gamepad : mGamepads)
-			gamepad->capture();
-
-		float rawXValue = 0.0f;
-		float rawYValue = 0.0f;
-
-		// Smooth mouse axes if needed
-		if (mMouseSmoothingEnabled)
-		{
-			rawXValue = smoothMouse((float)mMouseSampleAccumulator[0], 0);
-			rawYValue = smoothMouse((float)mMouseSampleAccumulator[1], 1);
-		}
-		else
-		{
-			rawXValue = (float)mMouseSampleAccumulator[0];
-			rawYValue = (float)mMouseSampleAccumulator[1];
-		}
-
-		rawXValue *= 0.1f;
-		rawYValue *= 0.1f;
-
-		mMouseSampleAccumulator[0] = 0;
-		mMouseSampleAccumulator[1] = 0;
-
-		RawAxisState xState;
-		xState.rel = -rawXValue;
-		onAxisMoved(0, xState, (UINT32)InputAxis::MouseX);
-
-		RawAxisState yState;
-		yState.rel = -rawYValue;
-		
-		onAxisMoved(0, yState, (UINT32)InputAxis::MouseY);
-	}
-
-	void RawInputHandler::_inputWindowChanged(const RenderWindow& win)
-	{
-		UINT64 hWnd = 0;
-		win.getCustomAttribute("WINDOW", &hWnd);
-
-		mKeyboard->changeCaptureContext(hWnd);
-		mMouse->changeCaptureContext(hWnd);
-
-		for (auto& gamepad : mGamepads)
-			gamepad->changeCaptureContext(hWnd);
-	}
-
-	void RawInputHandler::_notifyMouseMoved(INT32 relX, INT32 relY, INT32 relZ)
-	{
-		mMouseSampleAccumulator[0] += relX;
-		mMouseSampleAccumulator[1] += relY;
-
-		mTotalMouseNumSamples[0] += Math::roundToInt(Math::abs((float)relX));
-		mTotalMouseNumSamples[1] += Math::roundToInt(Math::abs((float)relY));
-
-		// Update sample times used for determining sampling rate. But only if something was
-		// actually sampled, and only if this isn't the first non-zero sample.
-		if (mLastMouseUpdateFrame != gTime().getFrameIdx())
-		{
-			if (relX != 0 && !Math::approxEquals(mMouseSmoothedAxis[0], 0.0f))
-				mTotalMouseSamplingTime[0] += gTime().getFrameDelta();
-
-			if (relY != 0 && !Math::approxEquals(mMouseSmoothedAxis[1], 0.0f))
-				mTotalMouseSamplingTime[1] += gTime().getFrameDelta();
-
-			mLastMouseUpdateFrame = gTime().getFrameIdx();
-		}
-
-		RawAxisState zState;
-		zState.rel = (float)relZ;
-
-		onAxisMoved(0, zState, (UINT32)InputAxis::MouseZ);
-	}
-
-	void RawInputHandler::_notifyAxisMoved(UINT32 gamepadIdx, UINT32 axisIdx, INT32 value)
-	{
-		// Move axis values into [-1.0f, 1.0f] range
-		float axisRange = Math::abs((float)Gamepad::MAX_AXIS) + Math::abs((float)Gamepad::MIN_AXIS);
-
-		RawAxisState axisState;
-		axisState.rel = ((value + Math::abs((float)Gamepad::MIN_AXIS)) / axisRange) * 2.0f - 1.0f;
-
-		onAxisMoved(gamepadIdx, axisState, axisIdx);
-	}
-
-	void RawInputHandler::_notifyButtonPressed(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp)
-	{
-		onButtonDown(deviceIdx, code, timestamp - mTimestampClockOffset);
-	}
-
-	void RawInputHandler::_notifyButtonReleased(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp)
-	{
-		onButtonUp(deviceIdx, code, timestamp - mTimestampClockOffset);
-	}
-
-	float RawInputHandler::smoothMouse(float value, UINT32 idx)
-	{
-		UINT32 sampleCount = 1;
-
-		float deltaTime = gTime().getFrameDelta();
-		if (deltaTime < 0.25f)
-		{
-			float secondsPerSample = mTotalMouseSamplingTime[idx] / mTotalMouseNumSamples[idx];
-
-			if (value == 0.0f)
-			{
-				mMouseZeroTime[idx] += deltaTime;
-				if (mMouseZeroTime[idx] < secondsPerSample)
-					value = mMouseSmoothedAxis[idx] * deltaTime / secondsPerSample;
-				else
-					mMouseSmoothedAxis[idx] = 0;
-			}
-			else
-			{
-				mMouseZeroTime[idx] = 0;
-				if (mMouseSmoothedAxis[idx] != 0)
-				{
-					if (deltaTime < secondsPerSample * (sampleCount + 1))
-						value = value * deltaTime / (secondsPerSample * sampleCount);
-					else
-						sampleCount = Math::roundToInt(deltaTime / secondsPerSample);
-				}
-
-				mMouseSmoothedAxis[idx] = value / sampleCount;
-			}
-		}
-		else
-		{
-			mMouseSmoothedAxis[idx] = 0.0f;
-			mMouseZeroTime[idx] = 0.0f;
-		}
-
-		return value;
-	}
-}

+ 0 - 131
Source/BansheeCore/Input/BsRawInputHandler.h

@@ -1,131 +0,0 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#pragma once
-
-#include "BsCorePrerequisites.h"
-#include "Input/BsInputFwd.h"
-#include "Utility/BsEvent.h"
-
-namespace bs
-{
-	class Mouse;
-	class Keyboard;
-	class Gamepad;
-	struct InputPrivateData;
-
-	/** @addtogroup Input-Internal
-	 *  @{
-	 */
-
-	/**
-	 * Contains relative position of an input axis. Relative state represents the difference between current and last state.
-	 */
-	struct RawAxisState
-	{
-		RawAxisState()
-		 :rel(0.0f)
-		{ }
-
-		float rel;
-	};
-
-	/**
-	 * Represents a specific way of acquiring low-level input. Input class (which provides a higher level input) must have 
-	 * at least one RawInputHandler attached. Raw input handlers receive input as sent by the hardware without OS 
-	 * modifications.
-	 */
-	class BS_CORE_EXPORT RawInputHandler
-	{
-	public:
-		RawInputHandler(UINT64 windowHandle);
-		virtual ~RawInputHandler();
-
-		/** Enables or disables mouse smoothing. Smoothing makes the changes to mouse axes more gradual. */
-		void setMouseSmoothing(bool enabled) { mMouseSmoothingEnabled = enabled; }
-
-		/** Returns the number of detected devices of the specified type. */
-		UINT32 getDeviceCount(InputDevice device) const;
-
-		/**
-		 * Triggered when user presses a button. Parameters include device index, button code of the pressed button, 
-		 * and a timestamp of the button press event.
-		 */
-		Event<void(UINT32, ButtonCode, UINT64)> onButtonDown;
-
-		/**
-		 * Triggered when user releases a button. Parameters include device index, button code of the released button, 
-		 * and a timestamp of the button release event.
-		 */
-		Event<void(UINT32, ButtonCode, UINT64)> onButtonUp;
-
-		/**
-		 * Triggered whenever the specified axis state changes. Parameters include device index, axis state data, and axis 
-		 * type.
-		 */
-		Event<void(UINT32, const RawAxisState&, UINT32)> onAxisMoved;
-
-		/** Called once per frame. Capture input here if needed. */
-		void _update();
-
-		/**
-		 * Called whenever the active window changes.
-		 *
-		 * @param[in]	win	Newly active window.
-		 */
-		void _inputWindowChanged(const RenderWindow& win);
-
-		/** Returns internal, platform specific privata data. */
-		InputPrivateData* _getPrivateData() const { return mPlatformData; }
-
-		/** Returns a handle to the window that is currently receiving input. */
-		UINT64 _getWindowHandle() const { return mWindowHandle; }
-
-		/** Called by Mouse when mouse movement is detected. */
-		void _notifyMouseMoved(INT32 relX, INT32 relY, INT32 relZ);
-
-		/** Called by any of the devices when analog axis movement is detected. */
-		void _notifyAxisMoved(UINT32 gamepadIdx, UINT32 axisIdx, INT32 value);
-
-		/** Called by any of the devices when a button is pressed. */
-		void _notifyButtonPressed(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp);
-
-		/** Called by any of the devices when a button is released. */
-		void _notifyButtonReleased(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp);
-	protected:
-		/** Performs platform specific input system initialization. */
-		void initialize();
-
-		/** Performs platform specific input system cleanup. */
-		void cleanUp();
-
-		/**
-		 * Smooths the input mouse axis value. Smoothing makes the changes to the axis more gradual depending on previous
-		 * values.
-		 *
-		 * @param[in]	value	Value to smooth.
-		 * @param[in]	idx		Index of the mouse axis to smooth, 0 - horizontal, 1 - vertical.
-		 * @return				Smoothed value.
-		 */
-		float smoothMouse(float value, UINT32 idx);
-
-		bool mMouseSmoothingEnabled;
-		UINT64 mWindowHandle;
-
-		Mouse* mMouse;
-		Keyboard* mKeyboard;
-		Vector<Gamepad*> mGamepads;
-
-		float mTotalMouseSamplingTime[2];
-		UINT32 mTotalMouseNumSamples[2];
-		float mMouseZeroTime[2];
-		INT32 mMouseSampleAccumulator[2];
-		float mMouseSmoothedAxis[2];
-		UINT64 mLastMouseUpdateFrame;
-
-		UINT64 mTimestampClockOffset;
-
-		InputPrivateData* mPlatformData;
-	};
-
-	/** @} */
-}

+ 3 - 3
Source/BansheeCore/Win32/BsWin32Gamepad.cpp

@@ -1,7 +1,7 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "Input/BsGamepad.h"
-#include "Input/BsRawInputHandler.h"
+#include "Input/BsInput.h"
 #include "Win32/BsWin32Input.h"
 #include "Error/BsException.h"
 
@@ -75,7 +75,7 @@ namespace bs
 	}
 
 	/** Handles a DirectInput POV event. */
-	void handlePOV(RawInputHandler* owner, Gamepad::Pimpl* m, int pov, DIDEVICEOBJECTDATA& di)
+	void handlePOV(Input* owner, Gamepad::Pimpl* m, int pov, DIDEVICEOBJECTDATA& di)
 	{
 		if (LOWORD(di.dwData) == 0xFFFF)
 		{
@@ -194,7 +194,7 @@ namespace bs
 		return (ButtonCode)(BC_GAMEPAD_BTN1 + (code - 15));
 	}
 
-	Gamepad::Gamepad(const String& name, const GamepadInfo& gamepadInfo, RawInputHandler* owner)
+	Gamepad::Gamepad(const String& name, const GamepadInfo& gamepadInfo, Input* owner)
 		: mName(name), mOwner(owner)
 	{
 		InputPrivateData* pvtData = owner->_getPrivateData();

+ 13 - 4
Source/BansheeCore/Win32/BsWin32Input.cpp

@@ -1,6 +1,6 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "Input/BsRawInputHandler.h"
+#include "Input/BsInput.h"
 #include "Error/BsException.h"
 #include "Win32/BsWin32Input.h"
 #include "Input/BsMouse.h"
@@ -143,7 +143,7 @@ namespace bs
 			CoUninitialize();
 	}
 
-	void RawInputHandler::initialize()
+	void Input::initRawInput()
 	{
 		mPlatformData = bs_new<InputPrivateData>();
 		
@@ -184,14 +184,23 @@ namespace bs
 			mGamepads.push_back(bs_new<Gamepad>(mPlatformData->gamepadInfos[i].name, mPlatformData->gamepadInfos[i], this));
 	}
 
-	void RawInputHandler::cleanUp()
+	void Input::cleanUpRawInput()
 	{
+		if (mMouse != nullptr)
+			bs_delete(mMouse);
+
+		if (mKeyboard != nullptr)
+			bs_delete(mKeyboard);
+
+		for (auto& gamepad : mGamepads)
+			bs_delete(gamepad);
+
 		mPlatformData->directInput->Release();
 
 		bs_delete(mPlatformData);
 	}
 
-	UINT32 RawInputHandler::getDeviceCount(InputDevice device) const
+	UINT32 Input::getDeviceCount(InputDevice device) const
 	{
 		switch(device)
 		{

+ 2 - 2
Source/BansheeCore/Win32/BsWin32Keyboard.cpp

@@ -1,7 +1,7 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "Input/BsKeyboard.h"
-#include "Input/BsRawInputHandler.h"
+#include "Input/BsInput.h"
 #include "Win32/BsWin32Input.h"
 #include "Error/BsException.h"
 
@@ -61,7 +61,7 @@ namespace bs
 		}
 	}
 
-	Keyboard::Keyboard(const String& name, RawInputHandler* owner)
+	Keyboard::Keyboard(const String& name, Input* owner)
 		: mName(name), mOwner(owner)
 	{
 		InputPrivateData* pvtData = owner->_getPrivateData();

+ 3 - 3
Source/BansheeCore/Win32/BsWin32Mouse.cpp

@@ -1,7 +1,7 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "Input/BsMouse.h"
-#include "Input/BsRawInputHandler.h"
+#include "Input/BsInput.h"
 #include "Win32/BsWin32Input.h"
 #include "Error/BsException.h"
 
@@ -60,7 +60,7 @@ namespace bs
 	}
 
 	/** Notifies the input handler that a mouse press or release occurred. Triggers an event in the input handler. */
-	void doMouseClick(RawInputHandler* owner, ButtonCode mouseButton, const DIDEVICEOBJECTDATA& data)
+	void doMouseClick(Input* owner, ButtonCode mouseButton, const DIDEVICEOBJECTDATA& data)
 	{
 		if (data.dwData & 0x80)
 			owner->_notifyButtonPressed(0, mouseButton, data.dwTimeStamp);
@@ -68,7 +68,7 @@ namespace bs
 			owner->_notifyButtonReleased(0, mouseButton, data.dwTimeStamp);
 	}
 
-	Mouse::Mouse(const String& name, RawInputHandler* owner)
+	Mouse::Mouse(const String& name, Input* owner)
 		: mName(name), mOwner(owner)
 	{
 		InputPrivateData* pvtData = owner->_getPrivateData();