|
|
@@ -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()
|