Merge pull request #24470 from fuzzard/release_20.3
[xbmc.git] / xbmc / input / IRTranslator.cpp
blob906e4f56e1eb51c0cff0f94625c86a7c7030fbf7
1 /*
2 * Copyright (C) 2017-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "IRTranslator.h"
11 #include "ServiceBroker.h"
12 #include "input/remote/IRRemote.h"
13 #include "profiles/ProfileManager.h"
14 #include "settings/SettingsComponent.h"
15 #include "utils/FileUtils.h"
16 #include "utils/StringUtils.h"
17 #include "utils/URIUtils.h"
18 #include "utils/XBMCTinyXML.h"
19 #include "utils/log.h"
21 #include <stdlib.h>
22 #include <vector>
24 void CIRTranslator::Load(const std::string& irMapName)
26 if (irMapName.empty())
27 return;
29 Clear();
31 bool success = false;
33 std::string irMapPath = URIUtils::AddFileToFolder("special://xbmc/system/", irMapName);
34 if (CFileUtils::Exists(irMapPath))
35 success |= LoadIRMap(irMapPath);
36 else
37 CLog::Log(LOGDEBUG, "CIRTranslator::Load - no system {} found, skipping", irMapName);
39 irMapPath =
40 CServiceBroker::GetSettingsComponent()->GetProfileManager()->GetUserDataItem(irMapName);
41 if (CFileUtils::Exists(irMapPath))
42 success |= LoadIRMap(irMapPath);
43 else
44 CLog::Log(LOGDEBUG, "CIRTranslator::Load - no userdata {} found, skipping", irMapName);
46 if (!success)
47 CLog::Log(LOGERROR, "CIRTranslator::Load - unable to load remote map {}", irMapName);
50 bool CIRTranslator::LoadIRMap(const std::string& irMapPath)
52 std::string remoteMapTag = URIUtils::GetFileName(irMapPath);
53 size_t lastindex = remoteMapTag.find_last_of('.');
54 if (lastindex != std::string::npos)
55 remoteMapTag = remoteMapTag.substr(0, lastindex);
56 StringUtils::ToLower(remoteMapTag);
58 // Load our xml file, and fill up our mapping tables
59 CXBMCTinyXML xmlDoc;
61 // Load the config file
62 CLog::Log(LOGINFO, "Loading {}", irMapPath);
63 if (!xmlDoc.LoadFile(irMapPath))
65 CLog::Log(LOGERROR, "{}, Line {}\n{}", irMapPath, xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
66 return false;
69 TiXmlElement* pRoot = xmlDoc.RootElement();
70 std::string strValue = pRoot->Value();
71 if (strValue != remoteMapTag)
73 CLog::Log(LOGERROR, "{} Doesn't contain <{}>", irMapPath, remoteMapTag);
74 return false;
77 // Run through our window groups
78 TiXmlNode* pRemote = pRoot->FirstChild();
79 while (pRemote != nullptr)
81 if (pRemote->Type() == TiXmlNode::TINYXML_ELEMENT)
83 const char* szRemote = pRemote->Value();
84 if (szRemote != nullptr)
86 TiXmlAttribute* pAttr = pRemote->ToElement()->FirstAttribute();
87 if (pAttr != nullptr)
88 MapRemote(pRemote, pAttr->Value());
91 pRemote = pRemote->NextSibling();
94 return true;
97 void CIRTranslator::MapRemote(TiXmlNode* pRemote, const std::string& szDevice)
99 CLog::Log(LOGINFO, "* Adding remote mapping for device '{}'", szDevice);
101 std::vector<std::string> remoteNames;
103 auto it = m_irRemotesMap.find(szDevice);
104 if (it == m_irRemotesMap.end())
105 m_irRemotesMap[szDevice].reset(new IRButtonMap);
107 const std::shared_ptr<IRButtonMap>& buttons = m_irRemotesMap[szDevice];
109 TiXmlElement* pButton = pRemote->FirstChildElement();
110 while (pButton != nullptr)
112 if (!pButton->NoChildren())
114 if (pButton->ValueStr() == "altname")
115 remoteNames.push_back(pButton->FirstChild()->ValueStr());
116 else
117 (*buttons)[pButton->FirstChild()->ValueStr()] = pButton->ValueStr();
119 pButton = pButton->NextSiblingElement();
122 for (const auto& remoteName : remoteNames)
124 CLog::Log(LOGINFO, "* Linking remote mapping for '{}' to '{}'", szDevice, remoteName);
125 m_irRemotesMap[remoteName] = buttons;
129 void CIRTranslator::Clear()
131 m_irRemotesMap.clear();
134 unsigned int CIRTranslator::TranslateButton(const std::string& szDevice,
135 const std::string& szButton)
137 // Find the device
138 auto it = m_irRemotesMap.find(szDevice);
139 if (it == m_irRemotesMap.end())
140 return 0;
142 // Find the button
143 auto it2 = (*it).second->find(szButton);
144 if (it2 == (*it).second->end())
145 return 0;
147 // Convert the button to code
148 if (StringUtils::CompareNoCase((*it2).second, "obc", 3) == 0)
149 return TranslateUniversalRemoteString((*it2).second);
151 return TranslateString((*it2).second);
154 uint32_t CIRTranslator::TranslateString(std::string strButton)
156 if (strButton.empty())
157 return 0;
159 uint32_t buttonCode = 0;
161 StringUtils::ToLower(strButton);
163 if (strButton == "left")
164 buttonCode = XINPUT_IR_REMOTE_LEFT;
165 else if (strButton == "right")
166 buttonCode = XINPUT_IR_REMOTE_RIGHT;
167 else if (strButton == "up")
168 buttonCode = XINPUT_IR_REMOTE_UP;
169 else if (strButton == "down")
170 buttonCode = XINPUT_IR_REMOTE_DOWN;
171 else if (strButton == "select")
172 buttonCode = XINPUT_IR_REMOTE_SELECT;
173 else if (strButton == "back")
174 buttonCode = XINPUT_IR_REMOTE_BACK;
175 else if (strButton == "menu")
176 buttonCode = XINPUT_IR_REMOTE_MENU;
177 else if (strButton == "info")
178 buttonCode = XINPUT_IR_REMOTE_INFO;
179 else if (strButton == "display")
180 buttonCode = XINPUT_IR_REMOTE_DISPLAY;
181 else if (strButton == "title")
182 buttonCode = XINPUT_IR_REMOTE_TITLE;
183 else if (strButton == "play")
184 buttonCode = XINPUT_IR_REMOTE_PLAY;
185 else if (strButton == "pause")
186 buttonCode = XINPUT_IR_REMOTE_PAUSE;
187 else if (strButton == "reverse")
188 buttonCode = XINPUT_IR_REMOTE_REVERSE;
189 else if (strButton == "forward")
190 buttonCode = XINPUT_IR_REMOTE_FORWARD;
191 else if (strButton == "skipplus")
192 buttonCode = XINPUT_IR_REMOTE_SKIP_PLUS;
193 else if (strButton == "skipminus")
194 buttonCode = XINPUT_IR_REMOTE_SKIP_MINUS;
195 else if (strButton == "stop")
196 buttonCode = XINPUT_IR_REMOTE_STOP;
197 else if (strButton == "zero")
198 buttonCode = XINPUT_IR_REMOTE_0;
199 else if (strButton == "one")
200 buttonCode = XINPUT_IR_REMOTE_1;
201 else if (strButton == "two")
202 buttonCode = XINPUT_IR_REMOTE_2;
203 else if (strButton == "three")
204 buttonCode = XINPUT_IR_REMOTE_3;
205 else if (strButton == "four")
206 buttonCode = XINPUT_IR_REMOTE_4;
207 else if (strButton == "five")
208 buttonCode = XINPUT_IR_REMOTE_5;
209 else if (strButton == "six")
210 buttonCode = XINPUT_IR_REMOTE_6;
211 else if (strButton == "seven")
212 buttonCode = XINPUT_IR_REMOTE_7;
213 else if (strButton == "eight")
214 buttonCode = XINPUT_IR_REMOTE_8;
215 else if (strButton == "nine")
216 buttonCode = XINPUT_IR_REMOTE_9;
217 // Additional keys from the media center extender for xbox remote
218 else if (strButton == "power")
219 buttonCode = XINPUT_IR_REMOTE_POWER;
220 else if (strButton == "mytv")
221 buttonCode = XINPUT_IR_REMOTE_MY_TV;
222 else if (strButton == "mymusic")
223 buttonCode = XINPUT_IR_REMOTE_MY_MUSIC;
224 else if (strButton == "mypictures")
225 buttonCode = XINPUT_IR_REMOTE_MY_PICTURES;
226 else if (strButton == "myvideo")
227 buttonCode = XINPUT_IR_REMOTE_MY_VIDEOS;
228 else if (strButton == "record")
229 buttonCode = XINPUT_IR_REMOTE_RECORD;
230 else if (strButton == "start")
231 buttonCode = XINPUT_IR_REMOTE_START;
232 else if (strButton == "volumeplus")
233 buttonCode = XINPUT_IR_REMOTE_VOLUME_PLUS;
234 else if (strButton == "volumeminus")
235 buttonCode = XINPUT_IR_REMOTE_VOLUME_MINUS;
236 else if (strButton == "channelplus")
237 buttonCode = XINPUT_IR_REMOTE_CHANNEL_PLUS;
238 else if (strButton == "channelminus")
239 buttonCode = XINPUT_IR_REMOTE_CHANNEL_MINUS;
240 else if (strButton == "pageplus")
241 buttonCode = XINPUT_IR_REMOTE_CHANNEL_PLUS;
242 else if (strButton == "pageminus")
243 buttonCode = XINPUT_IR_REMOTE_CHANNEL_MINUS;
244 else if (strButton == "mute")
245 buttonCode = XINPUT_IR_REMOTE_MUTE;
246 else if (strButton == "recordedtv")
247 buttonCode = XINPUT_IR_REMOTE_RECORDED_TV;
248 else if (strButton == "guide")
249 buttonCode = XINPUT_IR_REMOTE_GUIDE;
250 else if (strButton == "livetv")
251 buttonCode = XINPUT_IR_REMOTE_LIVE_TV;
252 else if (strButton == "liveradio")
253 buttonCode = XINPUT_IR_REMOTE_LIVE_RADIO;
254 else if (strButton == "epgsearch")
255 buttonCode = XINPUT_IR_REMOTE_EPG_SEARCH;
256 else if (strButton == "star")
257 buttonCode = XINPUT_IR_REMOTE_STAR;
258 else if (strButton == "hash")
259 buttonCode = XINPUT_IR_REMOTE_HASH;
260 else if (strButton == "clear")
261 buttonCode = XINPUT_IR_REMOTE_CLEAR;
262 else if (strButton == "enter")
263 buttonCode = XINPUT_IR_REMOTE_ENTER;
264 else if (strButton == "xbox")
265 buttonCode = XINPUT_IR_REMOTE_DISPLAY; // Same as display
266 else if (strButton == "playlist")
267 buttonCode = XINPUT_IR_REMOTE_PLAYLIST;
268 else if (strButton == "teletext")
269 buttonCode = XINPUT_IR_REMOTE_TELETEXT;
270 else if (strButton == "red")
271 buttonCode = XINPUT_IR_REMOTE_RED;
272 else if (strButton == "green")
273 buttonCode = XINPUT_IR_REMOTE_GREEN;
274 else if (strButton == "yellow")
275 buttonCode = XINPUT_IR_REMOTE_YELLOW;
276 else if (strButton == "blue")
277 buttonCode = XINPUT_IR_REMOTE_BLUE;
278 else if (strButton == "subtitle")
279 buttonCode = XINPUT_IR_REMOTE_SUBTITLE;
280 else if (strButton == "language")
281 buttonCode = XINPUT_IR_REMOTE_LANGUAGE;
282 else if (strButton == "eject")
283 buttonCode = XINPUT_IR_REMOTE_EJECT;
284 else if (strButton == "contentsmenu")
285 buttonCode = XINPUT_IR_REMOTE_CONTENTS_MENU;
286 else if (strButton == "rootmenu")
287 buttonCode = XINPUT_IR_REMOTE_ROOT_MENU;
288 else if (strButton == "topmenu")
289 buttonCode = XINPUT_IR_REMOTE_TOP_MENU;
290 else if (strButton == "dvdmenu")
291 buttonCode = XINPUT_IR_REMOTE_DVD_MENU;
292 else if (strButton == "print")
293 buttonCode = XINPUT_IR_REMOTE_PRINT;
294 else
295 CLog::Log(LOGERROR, "Remote Translator: Can't find button {}", strButton);
296 return buttonCode;
299 uint32_t CIRTranslator::TranslateUniversalRemoteString(const std::string& szButton)
301 if (szButton.empty() || szButton.length() < 4 || StringUtils::CompareNoCase(szButton, "obc", 3))
302 return 0;
304 const char* szCode = szButton.c_str() + 3;
306 // Button Code is 255 - OBC (Original Button Code) of the button
307 uint32_t buttonCode = 255 - atol(szCode);
308 if (buttonCode > 255)
309 buttonCode = 0;
311 return buttonCode;