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.
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"
24 void CIRTranslator::Load(const std::string
& irMapName
)
26 if (irMapName
.empty())
33 std::string irMapPath
= URIUtils::AddFileToFolder("special://xbmc/system/", irMapName
);
34 if (CFileUtils::Exists(irMapPath
))
35 success
|= LoadIRMap(irMapPath
);
37 CLog::Log(LOGDEBUG
, "CIRTranslator::Load - no system {} found, skipping", irMapName
);
40 CServiceBroker::GetSettingsComponent()->GetProfileManager()->GetUserDataItem(irMapName
);
41 if (CFileUtils::Exists(irMapPath
))
42 success
|= LoadIRMap(irMapPath
);
44 CLog::Log(LOGDEBUG
, "CIRTranslator::Load - no userdata {} found, skipping", irMapName
);
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
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());
69 TiXmlElement
* pRoot
= xmlDoc
.RootElement();
70 std::string strValue
= pRoot
->Value();
71 if (strValue
!= remoteMapTag
)
73 CLog::Log(LOGERROR
, "{} Doesn't contain <{}>", irMapPath
, remoteMapTag
);
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();
88 MapRemote(pRemote
, pAttr
->Value());
91 pRemote
= pRemote
->NextSibling();
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());
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
)
138 auto it
= m_irRemotesMap
.find(szDevice
);
139 if (it
== m_irRemotesMap
.end())
143 auto it2
= (*it
).second
->find(szButton
);
144 if (it2
== (*it
).second
->end())
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())
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
;
295 CLog::Log(LOGERROR
, "Remote Translator: Can't find button {}", strButton
);
299 uint32_t CIRTranslator::TranslateUniversalRemoteString(const std::string
& szButton
)
301 if (szButton
.empty() || szButton
.length() < 4 || StringUtils::CompareNoCase(szButton
, "obc", 3))
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)