diff options
Diffstat (limited to 'indra/llwindow/llgamecontroltranslator.cpp')
-rw-r--r-- | indra/llwindow/llgamecontroltranslator.cpp | 231 |
1 files changed, 83 insertions, 148 deletions
diff --git a/indra/llwindow/llgamecontroltranslator.cpp b/indra/llwindow/llgamecontroltranslator.cpp index 9654cb04f1..84468ab657 100644 --- a/indra/llwindow/llgamecontroltranslator.cpp +++ b/indra/llwindow/llgamecontroltranslator.cpp @@ -40,7 +40,7 @@ LLGameControlTranslator::LLGameControlTranslator() { } -void LLGameControlTranslator::setAvailableActions(ActionToMaskMap& action_to_mask) +void LLGameControlTranslator::setAvailableActionMasks(ActionToMaskMap& action_to_mask) { mActionToMask = std::move(action_to_mask); } @@ -48,11 +48,11 @@ void LLGameControlTranslator::setAvailableActions(ActionToMaskMap& action_to_mas LLGameControl::InputChannel LLGameControlTranslator::getChannelByAction(const std::string& action) const { LLGameControl::InputChannel channel; - ActionToMaskMap::const_iterator mask_itr = mActionToMask.find(action); + auto mask_itr = mActionToMask.find(action); if (mask_itr != mActionToMask.end()) { U32 mask = mask_itr->second; - LLGameControlTranslator::MaskToChannelMap::const_iterator channel_itr = mMaskToChannel.find(mask); + auto channel_itr = mMaskToChannel.find(mask); if (channel_itr != mMaskToChannel.end()) { channel = channel_itr->second; @@ -68,7 +68,7 @@ LLGameControl::InputChannel LLGameControlTranslator::getChannelByAction(const st if (mask_itr != mActionToMask.end()) { U32 mask = mask_itr->second; - LLGameControlTranslator::MaskToChannelMap::const_iterator channel_itr = mMaskToChannel.find(mask); + auto channel_itr = mMaskToChannel.find(mask); if (channel_itr != mMaskToChannel.end()) { channel = channel_itr->second; @@ -78,140 +78,95 @@ LLGameControl::InputChannel LLGameControlTranslator::getChannelByAction(const st return channel; } -void LLGameControlTranslator::setMappings(LLGameControlTranslator::NamedChannels& list) +void LLGameControlTranslator::setMappings(LLGameControlTranslator::NamedChannels& named_channels) { mMaskToChannel.clear(); mMappedFlags = 0; mPrevActiveFlags = 0; mCachedState.clear(); - for (auto& name_channel : list) + for (const auto& named_channel : named_channels) { - updateMap(name_channel.first, name_channel.second); + updateMap(named_channel.first, named_channel.second); } } -bool LLGameControlTranslator::updateMap(const std::string& name, const LLGameControl::InputChannel& channel) +void LLGameControlTranslator::updateMap(const std::string& action, const LLGameControl::InputChannel& channel) { - bool map_changed = false; - size_t name_length = name.length(); - if (name_length > 1) + // First, get the action name type + LLGameControl::ActionNameType actionNameType = LLGameControl::getActionNameType(action); + if (actionNameType == LLGameControl::ACTION_NAME_UNKNOWN || + actionNameType == LLGameControl::ACTION_NAME_FLYCAM) { - if (channel.isButton()) - { - map_changed = updateMapInternal(name, channel); - } - else if (channel.isAxis()) + LL_WARNS("SDL2") << "unmappable action='" << action << "' (type=" << actionNameType << ")" << LL_ENDL; + return; + } + + // Second, get the expected associated channel type (except of TYPE_NONE) + LLGameControl::InputChannel::Type expectedChannelType = + actionNameType == LLGameControl::ACTION_NAME_BINARY ? + LLGameControl::InputChannel::TYPE_BUTTON : + LLGameControl::InputChannel::TYPE_AXIS; + if (!channel.isNone() && (channel.mType != expectedChannelType)) + { + LL_WARNS("SDL2") << "unmappable channel (type=" << channel.mType << ")" + << " for action='" << action << "' (type=" << actionNameType << ")" << LL_ENDL; + return; + } + + if (actionNameType == LLGameControl::ACTION_NAME_ANALOG) // E.g., "push" + { + // Special (double) processing for analog action names + // sequentially adding '+' and '-' to the given action + updateMapInternal(action + "+", channel); + + // For the channel type TYPE_NONE we can map the same channel + // In fact, the mapping will be removed from the mapping list + if (channel.isNone()) { - U8 last_char = name.at(name_length - 1); - if (last_char == '+' || last_char == '-') - { - map_changed = updateMapInternal(name, channel); - } - else - { - // try to map both "name+" and "name-" - std::string new_name = name; - new_name.append("+"); - bool success = updateMapInternal(new_name, channel); - if (success) - { - new_name.data()[name_length] = '-'; - LLGameControl::InputChannel other_channel(channel.mType, channel.mIndex, -channel.mSign); - // TIED TRIGGER HACK: this works for XBox and similar controllers, - // and those are pretty much the only supported devices right now - // however TODO: figure out how to do this better. - // - // AXIS_TRIGGERLEFT and AXIS_TRIGGERRIGHT are separate axes and most devices - // only allow them to read positive, not negative. When used for motion control - // they are typically paired together. We assume as much here when computing - // the other_channel. - if (channel.mIndex == LLGameControl::AXIS_TRIGGERLEFT) - { - other_channel.mIndex = LLGameControl::AXIS_TRIGGERRIGHT; - other_channel.mSign = 1; - } - else if (channel.mIndex == LLGameControl::AXIS_TRIGGERRIGHT) - { - other_channel.mIndex = LLGameControl::AXIS_TRIGGERLEFT; - other_channel.mSign = 1; - } - updateMapInternal(new_name, other_channel); - map_changed = true; - } - } + updateMapInternal(action + "-", channel); } else { - // channel type is NONE, which means the action needs to be removed from the map - // but we don't know if it mapped to button or axis which is important because - // it if it axis then we need to also remove the other entry. - // So we try to look it up - ActionToMaskMap::iterator mask_itr = mActionToMask.find(name); - if (mask_itr != mActionToMask.end()) - { - // we found the action --> was it mapped to an axis? - bool is_axis = false; - U32 mask = mask_itr->second; - LLGameControlTranslator::MaskToChannelMap::iterator channel_itr = mMaskToChannel.find(mask); - if (channel_itr != mMaskToChannel.end()) - { - if (channel_itr->second.isAxis()) - { - // yes, it is an axis - is_axis = true; - } - } - // remove from map, whether button or axis - updateMapInternal(name, channel); + // For the channel type except of TYPE_NONE we construct the other channel + // with the same type and index but with the opposite sign + LLGameControl::InputChannel other_channel(channel.mType, channel.mIndex, -channel.mSign); - if (is_axis) - { - // also need to remove the other entry - std::string other_name = name; - if (other_name.data()[name.length() - 1] == '-') - { - other_name.data()[name.length() - 1] = '+'; - } - else - { - other_name.data()[name.length() - 1] = '-'; - } - // remove from map - updateMapInternal(other_name, channel); - } + // TIED TRIGGER HACK: this works for XBox and similar controllers, + // and those are pretty much the only supported devices right now + // however TODO: figure out how to do this better. + // + // AXIS_TRIGGERLEFT and AXIS_TRIGGERRIGHT are separate axes and most devices + // only allow them to read positive, not negative. When used for motion control + // they are typically paired together. We assume as much here when computing + // the other_channel. + if (channel.mIndex == LLGameControl::AXIS_TRIGGERLEFT) + { + other_channel.mIndex = LLGameControl::AXIS_TRIGGERRIGHT; + other_channel.mSign = 1; } - else if (name.data()[name.length() - 1] == '+' - || name.data()[name.length() - 1] == '-') + else if (channel.mIndex == LLGameControl::AXIS_TRIGGERRIGHT) { - // action was not found but name doesn't end with +/- - // maybe it is an axis-name sans the +/- on the end - // postfix with '+' and try again - std::string other_name = name; - other_name.append("+"); - map_changed = updateMapInternal(other_name, channel); - if (map_changed) - { - // that worked! now do the other one - other_name.data()[name.length()] = '-'; - updateMapInternal(other_name, channel); - } + other_channel.mIndex = LLGameControl::AXIS_TRIGGERLEFT; + other_channel.mSign = 1; } + updateMapInternal(action + "-", other_channel); } } + else + { + // Simple (single) processing for other action name types + updateMapInternal(action, channel); + } - if (map_changed) + // recompute mMappedFlags + mMappedFlags = 0; + for (auto& pair : mMaskToChannel) { - // recompute mMappedFlags - mMappedFlags = 0; - for (auto& pair : mMaskToChannel) - { - mMappedFlags |= pair.first; - } - mPrevActiveFlags = 0; - mCachedState.clear(); + mMappedFlags |= pair.first; } - return map_changed; + mPrevActiveFlags = 0; + mCachedState.clear(); } // Given external action_flags (i.e. raw avatar input) @@ -249,7 +204,7 @@ const LLGameControl::State& LLGameControlTranslator::computeStateFromFlags(U32 a } else if (channel.isButton()) { - mCachedState.mButtons |= (0x01U << channel.mIndex); + mCachedState.mButtons |= 0x01U << channel.mIndex; } } } @@ -295,46 +250,26 @@ U32 LLGameControlTranslator::computeFlagsFromState(const std::vector<S32>& axes, return action_flags; } -bool LLGameControlTranslator::updateMapInternal(const std::string& name, const LLGameControl::InputChannel& channel) +void LLGameControlTranslator::updateMapInternal(const std::string& name, const LLGameControl::InputChannel& channel) { - bool something_changed = false; - ActionToMaskMap::iterator mask_itr = mActionToMask.find(name); - if (mask_itr != mActionToMask.end()) + auto action_it = mActionToMask.find(name); + llassert(action_it != mActionToMask.end()); + U32 mask = action_it->second; + auto channel_it = mMaskToChannel.find(mask); + if (channel_it == mMaskToChannel.end()) { - U32 mask = mask_itr->second; - something_changed = addOrRemoveMaskMapping(mask, channel); + // create new mapping + mMaskToChannel[mask] = channel; } - return something_changed; -} - -bool LLGameControlTranslator::addOrRemoveMaskMapping(U32 mask, const LLGameControl::InputChannel& channel) -{ - bool success = false; - LLGameControlTranslator::MaskToChannelMap::iterator channel_itr = mMaskToChannel.find(mask); - if (channel_itr != mMaskToChannel.end()) + else if (channel.isNone()) { - LLGameControl::InputChannel old_channel = channel_itr->second; - if (old_channel.mType != channel.mType || old_channel.mIndex != channel.mIndex || old_channel.mSign != channel.mSign) - { - if (channel.isNone()) - { - // remove old mapping - mMaskToChannel.erase(channel_itr); - } - else - { - // update old mapping - channel_itr->second = channel; - } - success = true; - } + // remove old mapping + mMaskToChannel.erase(channel_it); } - else if (! channel.isNone()) + else { - // create new mapping - mMaskToChannel[mask] = channel; - success = true; + // update old mapping + channel_it->second = channel; } - return success; } |