summaryrefslogtreecommitdiffstats
path: root/xbmc/input/IRTranslator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/input/IRTranslator.cpp')
-rw-r--r--xbmc/input/IRTranslator.cpp312
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;
+}