diff options
Diffstat (limited to 'xbmc/input/IRTranslator.cpp')
-rw-r--r-- | xbmc/input/IRTranslator.cpp | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/xbmc/input/IRTranslator.cpp b/xbmc/input/IRTranslator.cpp new file mode 100644 index 0000000..906e4f5 --- /dev/null +++ b/xbmc/input/IRTranslator.cpp @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2017-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "IRTranslator.h" + +#include "ServiceBroker.h" +#include "input/remote/IRRemote.h" +#include "profiles/ProfileManager.h" +#include "settings/SettingsComponent.h" +#include "utils/FileUtils.h" +#include "utils/StringUtils.h" +#include "utils/URIUtils.h" +#include "utils/XBMCTinyXML.h" +#include "utils/log.h" + +#include <stdlib.h> +#include <vector> + +void CIRTranslator::Load(const std::string& irMapName) +{ + if (irMapName.empty()) + return; + + Clear(); + + bool success = false; + + std::string irMapPath = URIUtils::AddFileToFolder("special://xbmc/system/", irMapName); + if (CFileUtils::Exists(irMapPath)) + success |= LoadIRMap(irMapPath); + else + CLog::Log(LOGDEBUG, "CIRTranslator::Load - no system {} found, skipping", irMapName); + + irMapPath = + CServiceBroker::GetSettingsComponent()->GetProfileManager()->GetUserDataItem(irMapName); + if (CFileUtils::Exists(irMapPath)) + success |= LoadIRMap(irMapPath); + else + CLog::Log(LOGDEBUG, "CIRTranslator::Load - no userdata {} found, skipping", irMapName); + + if (!success) + CLog::Log(LOGERROR, "CIRTranslator::Load - unable to load remote map {}", irMapName); +} + +bool CIRTranslator::LoadIRMap(const std::string& irMapPath) +{ + std::string remoteMapTag = URIUtils::GetFileName(irMapPath); + size_t lastindex = remoteMapTag.find_last_of('.'); + if (lastindex != std::string::npos) + remoteMapTag = remoteMapTag.substr(0, lastindex); + StringUtils::ToLower(remoteMapTag); + + // Load our xml file, and fill up our mapping tables + CXBMCTinyXML xmlDoc; + + // Load the config file + CLog::Log(LOGINFO, "Loading {}", irMapPath); + if (!xmlDoc.LoadFile(irMapPath)) + { + CLog::Log(LOGERROR, "{}, Line {}\n{}", irMapPath, xmlDoc.ErrorRow(), xmlDoc.ErrorDesc()); + return false; + } + + TiXmlElement* pRoot = xmlDoc.RootElement(); + std::string strValue = pRoot->Value(); + if (strValue != remoteMapTag) + { + CLog::Log(LOGERROR, "{} Doesn't contain <{}>", irMapPath, remoteMapTag); + return false; + } + + // Run through our window groups + TiXmlNode* pRemote = pRoot->FirstChild(); + while (pRemote != nullptr) + { + if (pRemote->Type() == TiXmlNode::TINYXML_ELEMENT) + { + const char* szRemote = pRemote->Value(); + if (szRemote != nullptr) + { + TiXmlAttribute* pAttr = pRemote->ToElement()->FirstAttribute(); + if (pAttr != nullptr) + MapRemote(pRemote, pAttr->Value()); + } + } + pRemote = pRemote->NextSibling(); + } + + return true; +} + +void CIRTranslator::MapRemote(TiXmlNode* pRemote, const std::string& szDevice) +{ + CLog::Log(LOGINFO, "* Adding remote mapping for device '{}'", szDevice); + + std::vector<std::string> remoteNames; + + auto it = m_irRemotesMap.find(szDevice); + if (it == m_irRemotesMap.end()) + m_irRemotesMap[szDevice].reset(new IRButtonMap); + + const std::shared_ptr<IRButtonMap>& buttons = m_irRemotesMap[szDevice]; + + TiXmlElement* pButton = pRemote->FirstChildElement(); + while (pButton != nullptr) + { + if (!pButton->NoChildren()) + { + if (pButton->ValueStr() == "altname") + remoteNames.push_back(pButton->FirstChild()->ValueStr()); + else + (*buttons)[pButton->FirstChild()->ValueStr()] = pButton->ValueStr(); + } + pButton = pButton->NextSiblingElement(); + } + + for (const auto& remoteName : remoteNames) + { + CLog::Log(LOGINFO, "* Linking remote mapping for '{}' to '{}'", szDevice, remoteName); + m_irRemotesMap[remoteName] = buttons; + } +} + +void CIRTranslator::Clear() +{ + m_irRemotesMap.clear(); +} + +unsigned int CIRTranslator::TranslateButton(const std::string& szDevice, + const std::string& szButton) +{ + // Find the device + auto it = m_irRemotesMap.find(szDevice); + if (it == m_irRemotesMap.end()) + return 0; + + // Find the button + auto it2 = (*it).second->find(szButton); + if (it2 == (*it).second->end()) + return 0; + + // Convert the button to code + if (StringUtils::CompareNoCase((*it2).second, "obc", 3) == 0) + return TranslateUniversalRemoteString((*it2).second); + + return TranslateString((*it2).second); +} + +uint32_t CIRTranslator::TranslateString(std::string strButton) +{ + if (strButton.empty()) + return 0; + + uint32_t buttonCode = 0; + + StringUtils::ToLower(strButton); + + if (strButton == "left") + buttonCode = XINPUT_IR_REMOTE_LEFT; + else if (strButton == "right") + buttonCode = XINPUT_IR_REMOTE_RIGHT; + else if (strButton == "up") + buttonCode = XINPUT_IR_REMOTE_UP; + else if (strButton == "down") + buttonCode = XINPUT_IR_REMOTE_DOWN; + else if (strButton == "select") + buttonCode = XINPUT_IR_REMOTE_SELECT; + else if (strButton == "back") + buttonCode = XINPUT_IR_REMOTE_BACK; + else if (strButton == "menu") + buttonCode = XINPUT_IR_REMOTE_MENU; + else if (strButton == "info") + buttonCode = XINPUT_IR_REMOTE_INFO; + else if (strButton == "display") + buttonCode = XINPUT_IR_REMOTE_DISPLAY; + else if (strButton == "title") + buttonCode = XINPUT_IR_REMOTE_TITLE; + else if (strButton == "play") + buttonCode = XINPUT_IR_REMOTE_PLAY; + else if (strButton == "pause") + buttonCode = XINPUT_IR_REMOTE_PAUSE; + else if (strButton == "reverse") + buttonCode = XINPUT_IR_REMOTE_REVERSE; + else if (strButton == "forward") + buttonCode = XINPUT_IR_REMOTE_FORWARD; + else if (strButton == "skipplus") + buttonCode = XINPUT_IR_REMOTE_SKIP_PLUS; + else if (strButton == "skipminus") + buttonCode = XINPUT_IR_REMOTE_SKIP_MINUS; + else if (strButton == "stop") + buttonCode = XINPUT_IR_REMOTE_STOP; + else if (strButton == "zero") + buttonCode = XINPUT_IR_REMOTE_0; + else if (strButton == "one") + buttonCode = XINPUT_IR_REMOTE_1; + else if (strButton == "two") + buttonCode = XINPUT_IR_REMOTE_2; + else if (strButton == "three") + buttonCode = XINPUT_IR_REMOTE_3; + else if (strButton == "four") + buttonCode = XINPUT_IR_REMOTE_4; + else if (strButton == "five") + buttonCode = XINPUT_IR_REMOTE_5; + else if (strButton == "six") + buttonCode = XINPUT_IR_REMOTE_6; + else if (strButton == "seven") + buttonCode = XINPUT_IR_REMOTE_7; + else if (strButton == "eight") + buttonCode = XINPUT_IR_REMOTE_8; + else if (strButton == "nine") + buttonCode = XINPUT_IR_REMOTE_9; + // Additional keys from the media center extender for xbox remote + else if (strButton == "power") + buttonCode = XINPUT_IR_REMOTE_POWER; + else if (strButton == "mytv") + buttonCode = XINPUT_IR_REMOTE_MY_TV; + else if (strButton == "mymusic") + buttonCode = XINPUT_IR_REMOTE_MY_MUSIC; + else if (strButton == "mypictures") + buttonCode = XINPUT_IR_REMOTE_MY_PICTURES; + else if (strButton == "myvideo") + buttonCode = XINPUT_IR_REMOTE_MY_VIDEOS; + else if (strButton == "record") + buttonCode = XINPUT_IR_REMOTE_RECORD; + else if (strButton == "start") + buttonCode = XINPUT_IR_REMOTE_START; + else if (strButton == "volumeplus") + buttonCode = XINPUT_IR_REMOTE_VOLUME_PLUS; + else if (strButton == "volumeminus") + buttonCode = XINPUT_IR_REMOTE_VOLUME_MINUS; + else if (strButton == "channelplus") + buttonCode = XINPUT_IR_REMOTE_CHANNEL_PLUS; + else if (strButton == "channelminus") + buttonCode = XINPUT_IR_REMOTE_CHANNEL_MINUS; + else if (strButton == "pageplus") + buttonCode = XINPUT_IR_REMOTE_CHANNEL_PLUS; + else if (strButton == "pageminus") + buttonCode = XINPUT_IR_REMOTE_CHANNEL_MINUS; + else if (strButton == "mute") + buttonCode = XINPUT_IR_REMOTE_MUTE; + else if (strButton == "recordedtv") + buttonCode = XINPUT_IR_REMOTE_RECORDED_TV; + else if (strButton == "guide") + buttonCode = XINPUT_IR_REMOTE_GUIDE; + else if (strButton == "livetv") + buttonCode = XINPUT_IR_REMOTE_LIVE_TV; + else if (strButton == "liveradio") + buttonCode = XINPUT_IR_REMOTE_LIVE_RADIO; + else if (strButton == "epgsearch") + buttonCode = XINPUT_IR_REMOTE_EPG_SEARCH; + else if (strButton == "star") + buttonCode = XINPUT_IR_REMOTE_STAR; + else if (strButton == "hash") + buttonCode = XINPUT_IR_REMOTE_HASH; + else if (strButton == "clear") + buttonCode = XINPUT_IR_REMOTE_CLEAR; + else if (strButton == "enter") + buttonCode = XINPUT_IR_REMOTE_ENTER; + else if (strButton == "xbox") + buttonCode = XINPUT_IR_REMOTE_DISPLAY; // Same as display + else if (strButton == "playlist") + buttonCode = XINPUT_IR_REMOTE_PLAYLIST; + else if (strButton == "teletext") + buttonCode = XINPUT_IR_REMOTE_TELETEXT; + else if (strButton == "red") + buttonCode = XINPUT_IR_REMOTE_RED; + else if (strButton == "green") + buttonCode = XINPUT_IR_REMOTE_GREEN; + else if (strButton == "yellow") + buttonCode = XINPUT_IR_REMOTE_YELLOW; + else if (strButton == "blue") + buttonCode = XINPUT_IR_REMOTE_BLUE; + else if (strButton == "subtitle") + buttonCode = XINPUT_IR_REMOTE_SUBTITLE; + else if (strButton == "language") + buttonCode = XINPUT_IR_REMOTE_LANGUAGE; + else if (strButton == "eject") + buttonCode = XINPUT_IR_REMOTE_EJECT; + else if (strButton == "contentsmenu") + buttonCode = XINPUT_IR_REMOTE_CONTENTS_MENU; + else if (strButton == "rootmenu") + buttonCode = XINPUT_IR_REMOTE_ROOT_MENU; + else if (strButton == "topmenu") + buttonCode = XINPUT_IR_REMOTE_TOP_MENU; + else if (strButton == "dvdmenu") + buttonCode = XINPUT_IR_REMOTE_DVD_MENU; + else if (strButton == "print") + buttonCode = XINPUT_IR_REMOTE_PRINT; + else + CLog::Log(LOGERROR, "Remote Translator: Can't find button {}", strButton); + return buttonCode; +} + +uint32_t CIRTranslator::TranslateUniversalRemoteString(const std::string& szButton) +{ + if (szButton.empty() || szButton.length() < 4 || StringUtils::CompareNoCase(szButton, "obc", 3)) + return 0; + + const char* szCode = szButton.c_str() + 3; + + // Button Code is 255 - OBC (Original Button Code) of the button + uint32_t buttonCode = 255 - atol(szCode); + if (buttonCode > 255) + buttonCode = 0; + + return buttonCode; +} |