| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- #include "BsVirtualInput.h"
- #include "BsInput.h"
- #include "BsMath.h"
- #include "BsTime.h"
- using namespace std::placeholders;
- namespace BansheeEngine
- {
- VirtualInput::VirtualInput()
- :mActiveModifiers((UINT32)VButtonModifier::None)
- {
- mInputConfiguration = createConfiguration();
- Input::instance().onButtonDown.connect(std::bind(&VirtualInput::buttonDown, this, _1));
- Input::instance().onButtonUp.connect(std::bind(&VirtualInput::buttonUp, this, _1));
- }
- std::shared_ptr<InputConfiguration> VirtualInput::createConfiguration()
- {
- return bs_shared_ptr<InputConfiguration>();
- }
- void VirtualInput::setConfiguration(const std::shared_ptr<InputConfiguration>& input)
- {
- mInputConfiguration = input;
- // Note: Technically this is slightly wrong as it will
- // "forget" any buttons currently held down, but shouldn't matter much in practice.
- for (auto& deviceData : mDevices)
- deviceData.cachedStates.clear();
- }
- bool VirtualInput::isButtonDown(const VirtualButton& button, UINT32 deviceIdx) const
- {
- if (deviceIdx >= (UINT32)mDevices.size())
- return false;
- const Map<UINT32, ButtonData>& cachedStates = mDevices[deviceIdx].cachedStates;
- auto iterFind = cachedStates.find(button.buttonIdentifier);
- if (iterFind != cachedStates.end())
- return iterFind->second.state == ButtonState::ToggledOn;
-
- return false;
- }
- bool VirtualInput::isButtonUp(const VirtualButton& button, UINT32 deviceIdx) const
- {
- if (deviceIdx >= (UINT32)mDevices.size())
- return false;
- const Map<UINT32, ButtonData>& cachedStates = mDevices[deviceIdx].cachedStates;
- auto iterFind = cachedStates.find(button.buttonIdentifier);
- if (iterFind != cachedStates.end())
- return iterFind->second.state == ButtonState::ToggledOff;
- return false;
- }
- bool VirtualInput::isButtonHeld(const VirtualButton& button, UINT32 deviceIdx) const
- {
- if (deviceIdx >= (UINT32)mDevices.size())
- return false;
- const Map<UINT32, ButtonData>& cachedStates = mDevices[deviceIdx].cachedStates;
- auto iterFind = cachedStates.find(button.buttonIdentifier);
- if (iterFind != cachedStates.end())
- return iterFind->second.state == ButtonState::On || iterFind->second.state == ButtonState::ToggledOn;
- return false;
- }
- float VirtualInput::getAxisValue(const VirtualAxis& axis, UINT32 deviceIdx) const
- {
- VIRTUAL_AXIS_DESC axisDesc;
- if (mInputConfiguration->_getAxis(axis, axisDesc))
- {
- float axisValue = gInput().getAxisValue((UINT32)axisDesc.type, deviceIdx);
- if (axisDesc.deadZone > 0.0f)
- {
- // Scale to [-1, 1] range after removing the dead zone
- if (axisValue > 0)
- axisValue = std::max(0.f, axisValue - axisDesc.deadZone) / (1.0f - axisDesc.deadZone);
- else
- axisValue = -std::max(0.f, -axisValue - axisDesc.deadZone) / (1.0f - axisDesc.deadZone);
- }
- axisValue = Math::clamp(axisValue * axisDesc.sensitivity, -1.0f, 1.0f);
- if (axisDesc.invert)
- axisValue = -axisValue;
- return axisValue;
- }
- return 0.0f;
- }
- void VirtualInput::_update()
- {
- for (auto& deviceData : mDevices)
- {
- for (auto& state : deviceData.cachedStates)
- {
- if (state.second.state == ButtonState::ToggledOff)
- state.second.state = ButtonState::Off;
- else if (state.second.state == ButtonState::ToggledOn)
- state.second.state = ButtonState::On;
- }
- }
- bool hasEvents = true;
- UINT64 repeatInternal = mInputConfiguration->getRepeatInterval();
- UINT64 currentTime = gTime().getTimeMs();
- // Trigger all events
- while(hasEvents)
- {
- while(!mEvents.empty())
- {
- VirtualButtonEvent& event = mEvents.front();
- if(event.state == ButtonState::On)
- {
- if(!onButtonDown.empty())
- onButtonDown(event.button, event.deviceIdx);
- }
- else if(event.state == ButtonState::Off)
- {
- if(!onButtonUp.empty())
- onButtonUp(event.button, event.deviceIdx);
- }
- mEvents.pop();
- }
- // Queue up any repeatable events
- hasEvents = false;
- for (auto& deviceData : mDevices)
- {
- for (auto& state : deviceData.cachedStates)
- {
- if (state.second.state != ButtonState::On)
- continue;
- if (!state.second.allowRepeat)
- continue;
- UINT64 diff = currentTime - state.second.timestamp;
- if (diff >= repeatInternal)
- {
- state.second.timestamp += repeatInternal;
- VirtualButtonEvent event;
- event.button = state.second.button;
- event.state = ButtonState::On;
- event.deviceIdx = 0;
- mEvents.push(event);
- hasEvents = true;
- }
- }
- break; // Only repeat the first device. Repeat only makes sense for keyboard which there is only one of.
- }
- }
- }
- void VirtualInput::buttonDown(const ButtonEvent& event)
- {
- if(event.buttonCode == BC_LSHIFT || event.buttonCode == BC_RSHIFT)
- mActiveModifiers |= (UINT32)VButtonModifier::Shift;
- else if(event.buttonCode == BC_LCONTROL || event.buttonCode == BC_RCONTROL)
- mActiveModifiers |= (UINT32)VButtonModifier::Ctrl;
- else if(event.buttonCode == BC_LMENU || event.buttonCode == BC_RMENU)
- mActiveModifiers |= (UINT32)VButtonModifier::Alt;
- else
- {
- VirtualButton btn;
- VIRTUAL_BUTTON_DESC btnDesc;
- if(mInputConfiguration->_getButton(event.buttonCode, mActiveModifiers, btn, btnDesc))
- {
- while (event.deviceIdx >= (UINT32)mDevices.size())
- mDevices.push_back(DeviceData());
- Map<UINT32, ButtonData>& cachedStates = mDevices[event.deviceIdx].cachedStates;
- ButtonData& data = cachedStates[btn.buttonIdentifier];
- data.button = btn;
- data.state = ButtonState::ToggledOn;
- data.timestamp = event.timestamp;
- data.allowRepeat = btnDesc.repeatable;
- VirtualButtonEvent virtualEvent;
- virtualEvent.button = btn;
- virtualEvent.state = ButtonState::On;
- virtualEvent.deviceIdx = event.deviceIdx;
- mEvents.push(virtualEvent);
- }
- }
- }
- void VirtualInput::buttonUp(const ButtonEvent& event)
- {
- if(event.buttonCode == BC_LSHIFT || event.buttonCode == BC_RSHIFT)
- mActiveModifiers &= ~(UINT32)VButtonModifier::Shift;
- else if(event.buttonCode == BC_LCONTROL || event.buttonCode == BC_RCONTROL)
- mActiveModifiers &= ~(UINT32)VButtonModifier::Ctrl;
- else if(event.buttonCode == BC_LMENU || event.buttonCode == BC_RMENU)
- mActiveModifiers &= ~(UINT32)VButtonModifier::Alt;
- else
- {
- VirtualButton btn;
- VIRTUAL_BUTTON_DESC btnDesc;
- if(mInputConfiguration->_getButton(event.buttonCode, mActiveModifiers, btn, btnDesc))
- {
- while (event.deviceIdx >= (UINT32)mDevices.size())
- mDevices.push_back(DeviceData());
- Map<UINT32, ButtonData>& cachedStates = mDevices[event.deviceIdx].cachedStates;
- ButtonData& data = cachedStates[btn.buttonIdentifier];
- data.button = btn;
- data.state = ButtonState::ToggledOff;
- data.timestamp = event.timestamp;
- data.allowRepeat = btnDesc.repeatable;
- VirtualButtonEvent virtualEvent;
- virtualEvent.button = btn;
- virtualEvent.state = ButtonState::Off;
- virtualEvent.deviceIdx = event.deviceIdx;
- mEvents.push(virtualEvent);
- }
- }
- }
- VirtualInput& gVirtualInput()
- {
- return VirtualInput::instance();
- }
- }
|