2 * Copyright (C) 2005-2015 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with Kodi; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "ButtonTranslator.h"
27 #include "filesystem/Directory.h"
28 #include "filesystem/File.h"
29 #include "guilib/WindowIDs.h"
30 #include "input/Key.h"
31 #include "input/MouseStat.h"
32 #include "input/XBMC_keytable.h"
33 #include "interfaces/builtins/Builtins.h"
34 #include "profiles/ProfilesManager.h"
37 #include "utils/log.h"
38 #include "utils/RegExp.h"
39 #include "utils/StringUtils.h"
40 #include "utils/URIUtils.h"
41 #include "utils/XBMCTinyXML.h"
42 #include "XBIRRemote.h"
44 using namespace XFILE
;
58 static const ActionMapping actions
[] =
60 { "left" , ACTION_MOVE_LEFT
},
61 { "right" , ACTION_MOVE_RIGHT
},
62 { "up" , ACTION_MOVE_UP
},
63 { "down" , ACTION_MOVE_DOWN
},
64 { "pageup" , ACTION_PAGE_UP
},
65 { "pagedown" , ACTION_PAGE_DOWN
},
66 { "select" , ACTION_SELECT_ITEM
},
67 { "highlight" , ACTION_HIGHLIGHT_ITEM
},
68 { "parentdir" , ACTION_NAV_BACK
}, // backward compatibility
69 { "parentfolder" , ACTION_PARENT_DIR
},
70 { "back" , ACTION_NAV_BACK
},
71 { "menu" , ACTION_MENU
},
72 { "previousmenu" , ACTION_PREVIOUS_MENU
},
73 { "info" , ACTION_SHOW_INFO
},
74 { "pause" , ACTION_PAUSE
},
75 { "stop" , ACTION_STOP
},
76 { "skipnext" , ACTION_NEXT_ITEM
},
77 { "skipprevious" , ACTION_PREV_ITEM
},
78 { "fullscreen" , ACTION_SHOW_GUI
},
79 { "aspectratio" , ACTION_ASPECT_RATIO
},
80 { "stepforward" , ACTION_STEP_FORWARD
},
81 { "stepback" , ACTION_STEP_BACK
},
82 { "bigstepforward" , ACTION_BIG_STEP_FORWARD
},
83 { "bigstepback" , ACTION_BIG_STEP_BACK
},
84 { "chapterorbigstepforward" , ACTION_CHAPTER_OR_BIG_STEP_FORWARD
},
85 { "chapterorbigstepback" , ACTION_CHAPTER_OR_BIG_STEP_BACK
},
86 { "osd" , ACTION_SHOW_OSD
},
87 { "showsubtitles" , ACTION_SHOW_SUBTITLES
},
88 { "nextsubtitle" , ACTION_NEXT_SUBTITLE
},
89 { "cyclesubtitle" , ACTION_CYCLE_SUBTITLE
},
90 { "playerdebug" , ACTION_PLAYER_DEBUG
},
91 { "playerprocessinfo" , ACTION_PLAYER_PROCESS_INFO
},
92 { "nextpicture" , ACTION_NEXT_PICTURE
},
93 { "previouspicture" , ACTION_PREV_PICTURE
},
94 { "zoomout" , ACTION_ZOOM_OUT
},
95 { "zoomin" , ACTION_ZOOM_IN
},
96 { "playlist" , ACTION_SHOW_PLAYLIST
},
97 { "queue" , ACTION_QUEUE_ITEM
},
98 { "zoomnormal" , ACTION_ZOOM_LEVEL_NORMAL
},
99 { "zoomlevel1" , ACTION_ZOOM_LEVEL_1
},
100 { "zoomlevel2" , ACTION_ZOOM_LEVEL_2
},
101 { "zoomlevel3" , ACTION_ZOOM_LEVEL_3
},
102 { "zoomlevel4" , ACTION_ZOOM_LEVEL_4
},
103 { "zoomlevel5" , ACTION_ZOOM_LEVEL_5
},
104 { "zoomlevel6" , ACTION_ZOOM_LEVEL_6
},
105 { "zoomlevel7" , ACTION_ZOOM_LEVEL_7
},
106 { "zoomlevel8" , ACTION_ZOOM_LEVEL_8
},
107 { "zoomlevel9" , ACTION_ZOOM_LEVEL_9
},
108 { "nextcalibration" , ACTION_CALIBRATE_SWAP_ARROWS
},
109 { "resetcalibration" , ACTION_CALIBRATE_RESET
},
110 { "analogmove" , ACTION_ANALOG_MOVE
},
111 { "analogmovex" , ACTION_ANALOG_MOVE_X
},
112 { "analogmovey" , ACTION_ANALOG_MOVE_Y
},
113 { "rotate" , ACTION_ROTATE_PICTURE_CW
},
114 { "rotateccw" , ACTION_ROTATE_PICTURE_CCW
},
115 { "close" , ACTION_NAV_BACK
}, // backwards compatibility
116 { "subtitledelayminus" , ACTION_SUBTITLE_DELAY_MIN
},
117 { "subtitledelay" , ACTION_SUBTITLE_DELAY
},
118 { "subtitledelayplus" , ACTION_SUBTITLE_DELAY_PLUS
},
119 { "audiodelayminus" , ACTION_AUDIO_DELAY_MIN
},
120 { "audiodelay" , ACTION_AUDIO_DELAY
},
121 { "audiodelayplus" , ACTION_AUDIO_DELAY_PLUS
},
122 { "subtitleshiftup" , ACTION_SUBTITLE_VSHIFT_UP
},
123 { "subtitleshiftdown" , ACTION_SUBTITLE_VSHIFT_DOWN
},
124 { "subtitlealign" , ACTION_SUBTITLE_ALIGN
},
125 { "audionextlanguage" , ACTION_AUDIO_NEXT_LANGUAGE
},
126 { "verticalshiftup" , ACTION_VSHIFT_UP
},
127 { "verticalshiftdown" , ACTION_VSHIFT_DOWN
},
128 { "nextresolution" , ACTION_CHANGE_RESOLUTION
},
129 { "audiotoggledigital" , ACTION_TOGGLE_DIGITAL_ANALOG
},
130 { "number0" , REMOTE_0
},
131 { "number1" , REMOTE_1
},
132 { "number2" , REMOTE_2
},
133 { "number3" , REMOTE_3
},
134 { "number4" , REMOTE_4
},
135 { "number5" , REMOTE_5
},
136 { "number6" , REMOTE_6
},
137 { "number7" , REMOTE_7
},
138 { "number8" , REMOTE_8
},
139 { "number9" , REMOTE_9
},
140 { "smallstepback" , ACTION_SMALL_STEP_BACK
},
141 { "fastforward" , ACTION_PLAYER_FORWARD
},
142 { "rewind" , ACTION_PLAYER_REWIND
},
143 { "play" , ACTION_PLAYER_PLAY
},
144 { "playpause" , ACTION_PLAYER_PLAYPAUSE
},
145 { "switchplayer" , ACTION_SWITCH_PLAYER
},
146 { "delete" , ACTION_DELETE_ITEM
},
147 { "copy" , ACTION_COPY_ITEM
},
148 { "move" , ACTION_MOVE_ITEM
},
149 { "screenshot" , ACTION_TAKE_SCREENSHOT
},
150 { "rename" , ACTION_RENAME_ITEM
},
151 { "togglewatched" , ACTION_TOGGLE_WATCHED
},
152 { "scanitem" , ACTION_SCAN_ITEM
},
153 { "reloadkeymaps" , ACTION_RELOAD_KEYMAPS
},
154 { "volumeup" , ACTION_VOLUME_UP
},
155 { "volumedown" , ACTION_VOLUME_DOWN
},
156 { "mute" , ACTION_MUTE
},
157 { "backspace" , ACTION_BACKSPACE
},
158 { "scrollup" , ACTION_SCROLL_UP
},
159 { "scrolldown" , ACTION_SCROLL_DOWN
},
160 { "analogfastforward" , ACTION_ANALOG_FORWARD
},
161 { "analogrewind" , ACTION_ANALOG_REWIND
},
162 { "moveitemup" , ACTION_MOVE_ITEM_UP
},
163 { "moveitemdown" , ACTION_MOVE_ITEM_DOWN
},
164 { "contextmenu" , ACTION_CONTEXT_MENU
},
165 { "shift" , ACTION_SHIFT
},
166 { "symbols" , ACTION_SYMBOLS
},
167 { "cursorleft" , ACTION_CURSOR_LEFT
},
168 { "cursorright" , ACTION_CURSOR_RIGHT
},
169 { "showtime" , ACTION_SHOW_OSD_TIME
},
170 { "analogseekforward" , ACTION_ANALOG_SEEK_FORWARD
},
171 { "analogseekback" , ACTION_ANALOG_SEEK_BACK
},
172 { "showpreset" , ACTION_VIS_PRESET_SHOW
},
173 { "nextpreset" , ACTION_VIS_PRESET_NEXT
},
174 { "previouspreset" , ACTION_VIS_PRESET_PREV
},
175 { "lockpreset" , ACTION_VIS_PRESET_LOCK
},
176 { "randompreset" , ACTION_VIS_PRESET_RANDOM
},
177 { "increasevisrating" , ACTION_VIS_RATE_PRESET_PLUS
},
178 { "decreasevisrating" , ACTION_VIS_RATE_PRESET_MINUS
},
179 { "showvideomenu" , ACTION_SHOW_VIDEOMENU
},
180 { "enter" , ACTION_ENTER
},
181 { "increaserating" , ACTION_INCREASE_RATING
},
182 { "decreaserating" , ACTION_DECREASE_RATING
},
183 { "setrating" , ACTION_SET_RATING
},
184 { "togglefullscreen" , ACTION_TOGGLE_FULLSCREEN
},
185 { "nextscene" , ACTION_NEXT_SCENE
},
186 { "previousscene" , ACTION_PREV_SCENE
},
187 { "nextletter" , ACTION_NEXT_LETTER
},
188 { "prevletter" , ACTION_PREV_LETTER
},
189 { "jumpsms2" , ACTION_JUMP_SMS2
},
190 { "jumpsms3" , ACTION_JUMP_SMS3
},
191 { "jumpsms4" , ACTION_JUMP_SMS4
},
192 { "jumpsms5" , ACTION_JUMP_SMS5
},
193 { "jumpsms6" , ACTION_JUMP_SMS6
},
194 { "jumpsms7" , ACTION_JUMP_SMS7
},
195 { "jumpsms8" , ACTION_JUMP_SMS8
},
196 { "jumpsms9" , ACTION_JUMP_SMS9
},
197 { "filter" , ACTION_FILTER
},
198 { "filterclear" , ACTION_FILTER_CLEAR
},
199 { "filtersms2" , ACTION_FILTER_SMS2
},
200 { "filtersms3" , ACTION_FILTER_SMS3
},
201 { "filtersms4" , ACTION_FILTER_SMS4
},
202 { "filtersms5" , ACTION_FILTER_SMS5
},
203 { "filtersms6" , ACTION_FILTER_SMS6
},
204 { "filtersms7" , ACTION_FILTER_SMS7
},
205 { "filtersms8" , ACTION_FILTER_SMS8
},
206 { "filtersms9" , ACTION_FILTER_SMS9
},
207 { "firstpage" , ACTION_FIRST_PAGE
},
208 { "lastpage" , ACTION_LAST_PAGE
},
209 { "guiprofile" , ACTION_GUIPROFILE_BEGIN
},
210 { "red" , ACTION_TELETEXT_RED
},
211 { "green" , ACTION_TELETEXT_GREEN
},
212 { "yellow" , ACTION_TELETEXT_YELLOW
},
213 { "blue" , ACTION_TELETEXT_BLUE
},
214 { "increasepar" , ACTION_INCREASE_PAR
},
215 { "decreasepar" , ACTION_DECREASE_PAR
},
216 { "volampup" , ACTION_VOLAMP_UP
},
217 { "volampdown" , ACTION_VOLAMP_DOWN
},
218 { "volumeamplification" , ACTION_VOLAMP
},
219 { "createbookmark" , ACTION_CREATE_BOOKMARK
},
220 { "createepisodebookmark" , ACTION_CREATE_EPISODE_BOOKMARK
},
221 { "settingsreset" , ACTION_SETTINGS_RESET
},
222 { "settingslevelchange" , ACTION_SETTINGS_LEVEL_CHANGE
},
224 // 3D movie playback/GUI
225 { "stereomode" , ACTION_STEREOMODE_SELECT
}, // cycle 3D modes, for now an alias for next
226 { "nextstereomode" , ACTION_STEREOMODE_NEXT
},
227 { "previousstereomode" , ACTION_STEREOMODE_PREVIOUS
},
228 { "togglestereomode" , ACTION_STEREOMODE_TOGGLE
},
229 { "stereomodetomono" , ACTION_STEREOMODE_TOMONO
},
232 { "channelup" , ACTION_CHANNEL_UP
},
233 { "channeldown" , ACTION_CHANNEL_DOWN
},
234 { "previouschannelgroup" , ACTION_PREVIOUS_CHANNELGROUP
},
235 { "nextchannelgroup" , ACTION_NEXT_CHANNELGROUP
},
236 { "playpvr" , ACTION_PVR_PLAY
},
237 { "playpvrtv" , ACTION_PVR_PLAY_TV
},
238 { "playpvrradio" , ACTION_PVR_PLAY_RADIO
},
239 { "record" , ACTION_RECORD
},
240 { "togglecommskip" , ACTION_TOGGLE_COMMSKIP
},
241 { "showtimerrule" , ACTION_PVR_SHOW_TIMER_RULE
},
244 { "leftclick" , ACTION_MOUSE_LEFT_CLICK
},
245 { "rightclick" , ACTION_MOUSE_RIGHT_CLICK
},
246 { "middleclick" , ACTION_MOUSE_MIDDLE_CLICK
},
247 { "doubleclick" , ACTION_MOUSE_DOUBLE_CLICK
},
248 { "longclick" , ACTION_MOUSE_LONG_CLICK
},
249 { "wheelup" , ACTION_MOUSE_WHEEL_UP
},
250 { "wheeldown" , ACTION_MOUSE_WHEEL_DOWN
},
251 { "mousedrag" , ACTION_MOUSE_DRAG
},
252 { "mousemove" , ACTION_MOUSE_MOVE
},
255 { "tap" , ACTION_TOUCH_TAP
},
256 { "longpress" , ACTION_TOUCH_LONGPRESS
},
257 { "pangesture" , ACTION_GESTURE_PAN
},
258 { "zoomgesture" , ACTION_GESTURE_ZOOM
},
259 { "rotategesture" , ACTION_GESTURE_ROTATE
},
260 { "swipeleft" , ACTION_GESTURE_SWIPE_LEFT
},
261 { "swiperight" , ACTION_GESTURE_SWIPE_RIGHT
},
262 { "swipeup" , ACTION_GESTURE_SWIPE_UP
},
263 { "swipedown" , ACTION_GESTURE_SWIPE_DOWN
},
265 // Do nothing / error action
266 { "error" , ACTION_ERROR
},
267 { "noop" , ACTION_NOOP
}
270 bool CButtonTranslator::IsAnalog(int actionID
)
274 case ACTION_ANALOG_SEEK_FORWARD
:
275 case ACTION_ANALOG_SEEK_BACK
:
276 case ACTION_SCROLL_UP
:
277 case ACTION_SCROLL_DOWN
:
278 case ACTION_ANALOG_FORWARD
:
279 case ACTION_ANALOG_REWIND
:
280 case ACTION_ANALOG_MOVE
:
281 case ACTION_ANALOG_MOVE_X
:
282 case ACTION_ANALOG_MOVE_Y
:
283 case ACTION_CURSOR_LEFT
:
284 case ACTION_CURSOR_RIGHT
:
285 case ACTION_VOLUME_UP
:
286 case ACTION_VOLUME_DOWN
:
288 case ACTION_ZOOM_OUT
:
295 static const ActionMapping windows
[] =
297 { "home" , WINDOW_HOME
},
298 { "programs" , WINDOW_PROGRAMS
},
299 { "pictures" , WINDOW_PICTURES
},
300 { "filemanager" , WINDOW_FILES
},
301 { "settings" , WINDOW_SETTINGS_MENU
},
302 { "music" , WINDOW_MUSIC_NAV
},
303 { "videos" , WINDOW_VIDEO_NAV
},
304 { "tvchannels" , WINDOW_TV_CHANNELS
},
305 { "tvrecordings" , WINDOW_TV_RECORDINGS
},
306 { "tvguide" , WINDOW_TV_GUIDE
},
307 { "tvtimers" , WINDOW_TV_TIMERS
},
308 { "tvsearch" , WINDOW_TV_SEARCH
},
309 { "radiochannels" , WINDOW_RADIO_CHANNELS
},
310 { "radiorecordings" , WINDOW_RADIO_RECORDINGS
},
311 { "radioguide" , WINDOW_RADIO_GUIDE
},
312 { "radiotimers" , WINDOW_RADIO_TIMERS
},
313 { "radiosearch" , WINDOW_RADIO_SEARCH
},
314 { "gamecontrollers" , WINDOW_DIALOG_GAME_CONTROLLERS
},
315 { "pvrguideinfo" , WINDOW_DIALOG_PVR_GUIDE_INFO
},
316 { "pvrrecordinginfo" , WINDOW_DIALOG_PVR_RECORDING_INFO
},
317 { "pvrradiordsinfo" , WINDOW_DIALOG_PVR_RADIO_RDS_INFO
},
318 { "pvrtimersetting" , WINDOW_DIALOG_PVR_TIMER_SETTING
},
319 { "pvrgroupmanager" , WINDOW_DIALOG_PVR_GROUP_MANAGER
},
320 { "pvrchannelmanager" , WINDOW_DIALOG_PVR_CHANNEL_MANAGER
},
321 { "pvrguidesearch" , WINDOW_DIALOG_PVR_GUIDE_SEARCH
},
322 { "pvrchannelscan" , WINDOW_DIALOG_PVR_CHANNEL_SCAN
},
323 { "pvrupdateprogress" , WINDOW_DIALOG_PVR_UPDATE_PROGRESS
},
324 { "pvrosdchannels" , WINDOW_DIALOG_PVR_OSD_CHANNELS
},
325 { "pvrosdguide" , WINDOW_DIALOG_PVR_OSD_GUIDE
},
326 { "pvrosdteletext" , WINDOW_DIALOG_OSD_TELETEXT
},
327 { "systeminfo" , WINDOW_SYSTEM_INFORMATION
},
328 { "testpattern" , WINDOW_TEST_PATTERN
},
329 { "screencalibration" , WINDOW_SCREEN_CALIBRATION
},
330 { "systemsettings" , WINDOW_SETTINGS_SYSTEM
},
331 { "servicesettings" , WINDOW_SETTINGS_SERVICE
},
332 { "pvrsettings" , WINDOW_SETTINGS_MYPVR
},
333 { "playersettings" , WINDOW_SETTINGS_PLAYER
},
334 { "mediasettings" , WINDOW_SETTINGS_MEDIA
},
335 { "interfacesettings" , WINDOW_SETTINGS_INTERFACE
},
336 { "appearancesettings" , WINDOW_SETTINGS_INTERFACE
}, // backward compatibility to v16
337 { "videoplaylist" , WINDOW_VIDEO_PLAYLIST
},
338 { "loginscreen" , WINDOW_LOGIN_SCREEN
},
339 { "profiles" , WINDOW_SETTINGS_PROFILES
},
340 { "skinsettings" , WINDOW_SKIN_SETTINGS
},
341 { "addonbrowser" , WINDOW_ADDON_BROWSER
},
342 { "yesnodialog" , WINDOW_DIALOG_YES_NO
},
343 { "progressdialog" , WINDOW_DIALOG_PROGRESS
},
344 { "virtualkeyboard" , WINDOW_DIALOG_KEYBOARD
},
345 { "volumebar" , WINDOW_DIALOG_VOLUME_BAR
},
346 { "submenu" , WINDOW_DIALOG_SUB_MENU
},
347 { "favourites" , WINDOW_DIALOG_FAVOURITES
},
348 { "contextmenu" , WINDOW_DIALOG_CONTEXT_MENU
},
349 { "notification" , WINDOW_DIALOG_KAI_TOAST
},
350 { "numericinput" , WINDOW_DIALOG_NUMERIC
},
351 { "gamepadinput" , WINDOW_DIALOG_GAMEPAD
},
352 { "shutdownmenu" , WINDOW_DIALOG_BUTTON_MENU
},
353 { "playercontrols" , WINDOW_DIALOG_PLAYER_CONTROLS
},
354 { "playerprocessinfo" , WINDOW_DIALOG_PLAYER_PROCESS_INFO
},
355 { "seekbar" , WINDOW_DIALOG_SEEK_BAR
},
356 { "musicosd" , WINDOW_DIALOG_MUSIC_OSD
},
357 { "addonsettings" , WINDOW_DIALOG_ADDON_SETTINGS
},
358 { "visualisationpresetlist" , WINDOW_DIALOG_VIS_PRESET_LIST
},
359 { "osdcmssettings" , WINDOW_DIALOG_CMS_OSD_SETTINGS
},
360 { "osdvideosettings" , WINDOW_DIALOG_VIDEO_OSD_SETTINGS
},
361 { "osdaudiosettings" , WINDOW_DIALOG_AUDIO_OSD_SETTINGS
},
362 { "audiodspmanager" , WINDOW_DIALOG_AUDIO_DSP_MANAGER
},
363 { "osdaudiodspsettings" , WINDOW_DIALOG_AUDIO_DSP_OSD_SETTINGS
},
364 { "videobookmarks" , WINDOW_DIALOG_VIDEO_BOOKMARKS
},
365 { "filebrowser" , WINDOW_DIALOG_FILE_BROWSER
},
366 { "networksetup" , WINDOW_DIALOG_NETWORK_SETUP
},
367 { "mediasource" , WINDOW_DIALOG_MEDIA_SOURCE
},
368 { "profilesettings" , WINDOW_DIALOG_PROFILE_SETTINGS
},
369 { "locksettings" , WINDOW_DIALOG_LOCK_SETTINGS
},
370 { "contentsettings" , WINDOW_DIALOG_CONTENT_SETTINGS
},
371 { "songinformation" , WINDOW_DIALOG_SONG_INFO
},
372 { "smartplaylisteditor" , WINDOW_DIALOG_SMART_PLAYLIST_EDITOR
},
373 { "smartplaylistrule" , WINDOW_DIALOG_SMART_PLAYLIST_RULE
},
374 { "busydialog" , WINDOW_DIALOG_BUSY
},
375 { "pictureinfo" , WINDOW_DIALOG_PICTURE_INFO
},
376 { "accesspoints" , WINDOW_DIALOG_ACCESS_POINTS
},
377 { "fullscreeninfo" , WINDOW_DIALOG_FULLSCREEN_INFO
},
378 { "sliderdialog" , WINDOW_DIALOG_SLIDER
},
379 { "addoninformation" , WINDOW_DIALOG_ADDON_INFO
},
380 { "subtitlesearch" , WINDOW_DIALOG_SUBTITLES
},
381 { "musicplaylist" , WINDOW_MUSIC_PLAYLIST
},
382 { "musicplaylisteditor" , WINDOW_MUSIC_PLAYLIST_EDITOR
},
383 { "teletext" , WINDOW_DIALOG_OSD_TELETEXT
},
384 { "selectdialog" , WINDOW_DIALOG_SELECT
},
385 { "musicinformation" , WINDOW_DIALOG_MUSIC_INFO
},
386 { "okdialog" , WINDOW_DIALOG_OK
},
387 { "movieinformation" , WINDOW_DIALOG_VIDEO_INFO
},
388 { "textviewer" , WINDOW_DIALOG_TEXT_VIEWER
},
389 { "fullscreenvideo" , WINDOW_FULLSCREEN_VIDEO
},
390 { "fullscreenlivetv" , WINDOW_FULLSCREEN_LIVETV
}, // virtual window/keymap section for PVR specific bindings in fullscreen playback (which internally uses WINDOW_FULLSCREEN_VIDEO)
391 { "fullscreenradio" , WINDOW_FULLSCREEN_RADIO
}, // virtual window for fullscreen radio, uses WINDOW_VISUALISATION as fallback
392 { "visualisation" , WINDOW_VISUALISATION
},
393 { "slideshow" , WINDOW_SLIDESHOW
},
394 { "weather" , WINDOW_WEATHER
},
395 { "screensaver" , WINDOW_SCREENSAVER
},
396 { "videoosd" , WINDOW_DIALOG_VIDEO_OSD
},
397 { "videomenu" , WINDOW_VIDEO_MENU
},
398 { "videotimeseek" , WINDOW_VIDEO_TIME_SEEK
},
399 { "startwindow" , WINDOW_START
},
400 { "startup" , WINDOW_STARTUP_ANIM
},
401 { "peripheralsettings" , WINDOW_DIALOG_PERIPHERAL_SETTINGS
},
402 { "extendedprogressdialog" , WINDOW_DIALOG_EXT_PROGRESS
},
403 { "mediafilter" , WINDOW_DIALOG_MEDIA_FILTER
},
404 { "addon" , WINDOW_ADDON_START
},
405 { "eventlog" , WINDOW_EVENT_LOG
},
406 { "tvtimerrules" , WINDOW_TV_TIMER_RULES
},
407 { "radiotimerrules" , WINDOW_RADIO_TIMER_RULES
}
410 static const ActionMapping mousekeys
[] =
412 { "click" , KEY_MOUSE_CLICK
},
413 { "leftclick" , KEY_MOUSE_CLICK
},
414 { "rightclick" , KEY_MOUSE_RIGHTCLICK
},
415 { "middleclick" , KEY_MOUSE_MIDDLECLICK
},
416 { "doubleclick" , KEY_MOUSE_DOUBLE_CLICK
},
417 { "longclick" , KEY_MOUSE_LONG_CLICK
},
418 { "wheelup" , KEY_MOUSE_WHEEL_UP
},
419 { "wheeldown" , KEY_MOUSE_WHEEL_DOWN
},
420 { "mousemove" , KEY_MOUSE_MOVE
},
421 { "mousedrag" , KEY_MOUSE_DRAG
},
422 { "mousedragstart" , KEY_MOUSE_DRAG_START
},
423 { "mousedragend" , KEY_MOUSE_DRAG_END
},
424 { "mouserdrag" , KEY_MOUSE_RDRAG
},
425 { "mouserdragstart" , KEY_MOUSE_RDRAG_START
},
426 { "mouserdragend" , KEY_MOUSE_RDRAG_END
}
429 static const ActionMapping touchcommands
[] =
431 { "tap" , ACTION_TOUCH_TAP
},
432 { "longpress" , ACTION_TOUCH_LONGPRESS
},
433 { "pan" , ACTION_GESTURE_PAN
},
434 { "zoom" , ACTION_GESTURE_ZOOM
},
435 { "rotate" , ACTION_GESTURE_ROTATE
},
436 { "swipeleft" , ACTION_GESTURE_SWIPE_LEFT
},
437 { "swiperight" , ACTION_GESTURE_SWIPE_RIGHT
},
438 { "swipeup" , ACTION_GESTURE_SWIPE_UP
},
439 { "swipedown" , ACTION_GESTURE_SWIPE_DOWN
}
442 static const WindowMapping fallbackWindows
[] =
444 { WINDOW_FULLSCREEN_LIVETV
, WINDOW_FULLSCREEN_VIDEO
},
445 { WINDOW_FULLSCREEN_RADIO
, WINDOW_VISUALISATION
}
448 #ifdef TARGET_WINDOWS
449 static const ActionMapping appcommands
[] =
451 { "browser_back" , APPCOMMAND_BROWSER_BACKWARD
},
452 { "browser_forward" , APPCOMMAND_BROWSER_FORWARD
},
453 { "browser_refresh" , APPCOMMAND_BROWSER_REFRESH
},
454 { "browser_stop" , APPCOMMAND_BROWSER_STOP
},
455 { "browser_search" , APPCOMMAND_BROWSER_SEARCH
},
456 { "browser_favorites" , APPCOMMAND_BROWSER_FAVORITES
},
457 { "browser_home" , APPCOMMAND_BROWSER_HOME
},
458 { "volume_mute" , APPCOMMAND_VOLUME_MUTE
},
459 { "volume_down" , APPCOMMAND_VOLUME_DOWN
},
460 { "volume_up" , APPCOMMAND_VOLUME_UP
},
461 { "next_track" , APPCOMMAND_MEDIA_NEXTTRACK
},
462 { "prev_track" , APPCOMMAND_MEDIA_PREVIOUSTRACK
},
463 { "stop" , APPCOMMAND_MEDIA_STOP
},
464 { "play_pause" , APPCOMMAND_MEDIA_PLAY_PAUSE
},
465 { "launch_mail" , APPCOMMAND_LAUNCH_MAIL
},
466 { "launch_media_select" , APPCOMMAND_LAUNCH_MEDIA_SELECT
},
467 { "launch_app1" , APPCOMMAND_LAUNCH_APP1
},
468 { "launch_app2" , APPCOMMAND_LAUNCH_APP2
},
469 { "play" , APPCOMMAND_MEDIA_PLAY
},
470 { "pause" , APPCOMMAND_MEDIA_PAUSE
},
471 { "fastforward" , APPCOMMAND_MEDIA_FAST_FORWARD
},
472 { "rewind" , APPCOMMAND_MEDIA_REWIND
},
473 { "channelup" , APPCOMMAND_MEDIA_CHANNEL_UP
},
474 { "channeldown" , APPCOMMAND_MEDIA_CHANNEL_DOWN
}
478 CButtonTranslator
& CButtonTranslator::GetInstance()
480 static CButtonTranslator sl_instance
;
484 CButtonTranslator::CButtonTranslator()
486 m_deviceList
.clear();
490 #if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
491 void CButtonTranslator::ClearLircButtonMapEntries()
493 std::vector
<lircButtonMap
*> maps
;
494 for (std::map
<std::string
,lircButtonMap
*>::iterator it
= lircRemotesMap
.begin();
495 it
!= lircRemotesMap
.end();++it
)
496 maps
.push_back(it
->second
);
497 sort(maps
.begin(),maps
.end());
498 std::vector
<lircButtonMap
*>::iterator itend
= unique(maps
.begin(),maps
.end());
499 for (std::vector
<lircButtonMap
*>::iterator it
= maps
.begin(); it
!= itend
;++it
)
504 CButtonTranslator::~CButtonTranslator()
506 #if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
507 ClearLircButtonMapEntries();
511 // Add the supplied device name to the list of connected devices
512 void CButtonTranslator::AddDevice(std::string
& strDevice
)
514 // Only add the device if it isn't already in the list
515 std::list
<std::string
>::iterator it
;
516 for (it
= m_deviceList
.begin(); it
!= m_deviceList
.end(); ++it
)
517 if (*it
== strDevice
)
521 m_deviceList
.push_back(strDevice
);
524 // New device added so reload the key mappings
528 void CButtonTranslator::RemoveDevice(std::string
& strDevice
)
531 std::list
<std::string
>::iterator it
;
532 for (it
= m_deviceList
.begin(); it
!= m_deviceList
.end(); ++it
)
533 if (*it
== strDevice
)
535 if (it
== m_deviceList
.end())
539 m_deviceList
.remove(strDevice
);
541 // Device removed so reload the key mappings
545 bool CButtonTranslator::Load(bool AlwaysLoad
)
547 m_translatorMap
.clear();
549 // Directories to search for keymaps. They're applied in this order,
550 // so keymaps in profile/keymaps/ override e.g. system/keymaps
551 static const char* DIRS_TO_CHECK
[] = {
552 "special://xbmc/system/keymaps/",
553 "special://masterprofile/keymaps/",
554 "special://profile/keymaps/"
556 bool success
= false;
558 for (unsigned int dirIndex
= 0; dirIndex
< ARRAY_SIZE(DIRS_TO_CHECK
); ++dirIndex
)
560 if (XFILE::CDirectory::Exists(DIRS_TO_CHECK
[dirIndex
]))
563 XFILE::CDirectory::GetDirectory(DIRS_TO_CHECK
[dirIndex
], files
, ".xml");
564 // Sort the list for filesystem based priorities, e.g. 01-keymap.xml, 02-keymap-overrides.xml
565 files
.Sort(SortByFile
, SortOrderAscending
);
566 for(int fileIndex
= 0; fileIndex
<files
.Size(); ++fileIndex
)
568 if (!files
[fileIndex
]->m_bIsFolder
)
569 success
|= LoadKeymap(files
[fileIndex
]->GetPath());
572 // Load mappings for any HID devices we have connected
573 std::list
<std::string
>::iterator it
;
574 for (it
= m_deviceList
.begin(); it
!= m_deviceList
.end(); ++it
)
576 std::string devicedir
= DIRS_TO_CHECK
[dirIndex
];
577 devicedir
.append(*it
);
578 devicedir
.append("/");
579 if( XFILE::CDirectory::Exists(devicedir
) )
582 XFILE::CDirectory::GetDirectory(devicedir
, files
, ".xml");
583 // Sort the list for filesystem based priorities, e.g. 01-keymap.xml, 02-keymap-overrides.xml
584 files
.Sort(SortByFile
, SortOrderAscending
);
585 for(int fileIndex
= 0; fileIndex
<files
.Size(); ++fileIndex
)
587 if (!files
[fileIndex
]->m_bIsFolder
)
588 success
|= LoadKeymap(files
[fileIndex
]->GetPath());
597 CLog::Log(LOGERROR
, "Error loading keymaps from: %s or %s or %s", DIRS_TO_CHECK
[0], DIRS_TO_CHECK
[1], DIRS_TO_CHECK
[2]);
601 #if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
603 #define REMOTEMAP "Lircmap.xml"
605 #define REMOTEMAP "IRSSmap.xml"
607 std::string lircmapPath
= URIUtils::AddFileToFolder("special://xbmc/system/", REMOTEMAP
);
608 lircRemotesMap
.clear();
609 if(CFile::Exists(lircmapPath
))
610 success
|= LoadLircMap(lircmapPath
);
612 CLog::Log(LOGDEBUG
, "CButtonTranslator::Load - no system %s found, skipping", REMOTEMAP
);
614 lircmapPath
= CProfilesManager::GetInstance().GetUserDataItem(REMOTEMAP
);
615 if(CFile::Exists(lircmapPath
))
616 success
|= LoadLircMap(lircmapPath
);
618 CLog::Log(LOGDEBUG
, "CButtonTranslator::Load - no userdata %s found, skipping", REMOTEMAP
);
621 CLog::Log(LOGERROR
, "CButtonTranslator::Load - unable to load remote map %s", REMOTEMAP
);
622 // don't return false - it is to only indicate a fatal error (which this is not)
630 bool CButtonTranslator::LoadKeymap(const std::string
&keymapPath
)
634 CLog::Log(LOGINFO
, "Loading %s", keymapPath
.c_str());
635 if (!xmlDoc
.LoadFile(keymapPath
))
637 CLog::Log(LOGERROR
, "Error loading keymap: %s, Line %d\n%s", keymapPath
.c_str(), xmlDoc
.ErrorRow(), xmlDoc
.ErrorDesc());
640 TiXmlElement
* pRoot
= xmlDoc
.RootElement();
643 CLog::Log(LOGERROR
, "Error getting keymap root: %s", keymapPath
.c_str());
646 std::string strValue
= pRoot
->Value();
647 if ( strValue
!= "keymap")
649 CLog::Log(LOGERROR
, "%s Doesn't contain <keymap>", keymapPath
.c_str());
652 // run through our window groups
653 TiXmlNode
* pWindow
= pRoot
->FirstChild();
656 if (pWindow
->Type() == TiXmlNode::TINYXML_ELEMENT
)
658 int windowID
= WINDOW_INVALID
;
659 const char *szWindow
= pWindow
->Value();
662 if (strcmpi(szWindow
, "global") == 0)
665 windowID
= TranslateWindow(szWindow
);
667 MapWindowActions(pWindow
, windowID
);
669 pWindow
= pWindow
->NextSibling();
675 bool CButtonTranslator::LoadLircMap(const std::string
&lircmapPath
)
678 #define REMOTEMAPTAG "lircmap"
680 #define REMOTEMAPTAG "irssmap"
682 // load our xml file, and fill up our mapping tables
685 // Load the config file
686 CLog::Log(LOGINFO
, "Loading %s", lircmapPath
.c_str());
687 if (!xmlDoc
.LoadFile(lircmapPath
))
689 CLog::Log(LOGERROR
, "%s, Line %d\n%s", lircmapPath
.c_str(), xmlDoc
.ErrorRow(), xmlDoc
.ErrorDesc());
690 return false; // This is so people who don't have the file won't fail, just warn
693 TiXmlElement
* pRoot
= xmlDoc
.RootElement();
694 std::string strValue
= pRoot
->Value();
695 if (strValue
!= REMOTEMAPTAG
)
697 CLog::Log(LOGERROR
, "%sl Doesn't contain <%s>", lircmapPath
.c_str(), REMOTEMAPTAG
);
701 // run through our window groups
702 TiXmlNode
* pRemote
= pRoot
->FirstChild();
705 if (pRemote
->Type() == TiXmlNode::TINYXML_ELEMENT
)
707 const char *szRemote
= pRemote
->Value();
710 TiXmlAttribute
* pAttr
= pRemote
->ToElement()->FirstAttribute();
712 MapRemote(pRemote
, pAttr
->Value());
715 pRemote
= pRemote
->NextSibling();
721 void CButtonTranslator::MapRemote(TiXmlNode
*pRemote
, const char* szDevice
)
723 CLog::Log(LOGINFO
, "* Adding remote mapping for device '%s'", szDevice
);
724 std::vector
<std::string
> RemoteNames
;
725 std::map
<std::string
, lircButtonMap
*>::iterator it
= lircRemotesMap
.find(szDevice
);
726 if (it
== lircRemotesMap
.end())
727 lircRemotesMap
[szDevice
] = new lircButtonMap
;
728 lircButtonMap
& buttons
= *lircRemotesMap
[szDevice
];
730 TiXmlElement
*pButton
= pRemote
->FirstChildElement();
733 if (!pButton
->NoChildren())
735 if (pButton
->ValueStr() == "altname")
736 RemoteNames
.push_back(pButton
->FirstChild()->ValueStr());
738 buttons
[pButton
->FirstChild()->ValueStr()] = pButton
->ValueStr();
740 pButton
= pButton
->NextSiblingElement();
742 for (std::vector
<std::string
>::iterator it
= RemoteNames
.begin();
743 it
!= RemoteNames
.end();++it
)
745 CLog::Log(LOGINFO
, "* Linking remote mapping for '%s' to '%s'", szDevice
, it
->c_str());
746 lircRemotesMap
[*it
] = &buttons
;
750 int CButtonTranslator::TranslateLircRemoteString(const char* szDevice
, const char *szButton
)
753 std::map
<std::string
, lircButtonMap
*>::iterator it
= lircRemotesMap
.find(szDevice
);
754 if (it
== lircRemotesMap
.end())
758 lircButtonMap::iterator it2
= (*it
).second
->find(szButton
);
759 if (it2
== (*it
).second
->end())
762 // Convert the button to code
763 if (strnicmp((*it2
).second
.c_str(), "obc", 3) == 0)
764 return TranslateUniversalRemoteString((*it2
).second
.c_str());
766 return TranslateRemoteString((*it2
).second
.c_str());
769 int CButtonTranslator::GetCustomControllerActionCode(int windowId
, int buttonId
, const CustomControllerWindowMap
*windowMap
, std::string
& strAction
) const
773 auto it
= windowMap
->find(windowId
);
774 if (it
!= windowMap
->end())
776 const CustomControllerButtonMap
&buttonMap
= it
->second
;
777 auto it2
= buttonMap
.find(buttonId
);
778 if (it2
!= buttonMap
.end())
780 strAction
= it2
->second
;
781 TranslateActionString(strAction
.c_str(), action
);
788 bool CButtonTranslator::TranslateCustomControllerString(int windowId
, const std::string
& controllerName
, int buttonId
, int& action
, std::string
& strAction
)
790 // resolve the correct custom controller
791 auto it
= m_customControllersMap
.find(controllerName
);
792 if (it
== m_customControllersMap
.end())
797 const CustomControllerWindowMap
*wmap
= &it
->second
;
799 // try to get the action from the current window
800 action
= GetCustomControllerActionCode(windowId
, buttonId
, wmap
, strAction
);
802 // if it's invalid, try to get it from a fallback window or the global map
805 int fallbackWindow
= GetFallbackWindow(windowId
);
806 if (fallbackWindow
> -1)
807 action
= GetCustomControllerActionCode(fallbackWindow
, buttonId
, wmap
, strAction
);
808 // still no valid action? use global map
810 action
= GetCustomControllerActionCode(-1, buttonId
, wmap
, strAction
);
817 bool CButtonTranslator::TranslateTouchAction(int window
, int touchAction
, int touchPointers
, int &action
, std::string
&actionString
)
820 if (touchPointers
<= 0)
823 touchAction
+= touchPointers
- 1;
824 touchAction
|= KEY_TOUCH
;
826 action
= GetTouchActionCode(window
, touchAction
, actionString
);
829 int fallbackWindow
= GetFallbackWindow(window
);
830 if (fallbackWindow
> -1)
831 action
= GetTouchActionCode(fallbackWindow
, touchAction
, actionString
);
833 action
= GetTouchActionCode(-1, touchAction
, actionString
);
839 int CButtonTranslator::GetActionCode(int window
, int action
)
841 std::map
<int, buttonMap
>::const_iterator it
= m_translatorMap
.find(window
);
842 if (it
== m_translatorMap
.end())
845 buttonMap::const_iterator it2
= it
->second
.find(action
);
846 if (it2
== it
->second
.end())
849 return it2
->second
.id
;
852 void CButtonTranslator::GetActions(std::vector
<std::string
> &actionList
)
854 unsigned int size
= sizeof(actions
) / sizeof(ActionMapping
);
856 actionList
.reserve(size
);
857 for (unsigned int index
= 0; index
< size
; index
++)
858 actionList
.push_back(actions
[index
].name
);
861 void CButtonTranslator::GetWindows(std::vector
<std::string
> &windowList
)
863 unsigned int size
= sizeof(windows
) / sizeof(ActionMapping
);
865 windowList
.reserve(size
);
866 for (unsigned int index
= 0; index
< size
; index
++)
867 windowList
.push_back(windows
[index
].name
);
870 int CButtonTranslator::GetFallbackWindow(int windowID
)
872 for (unsigned int index
= 0; index
< ARRAY_SIZE(fallbackWindows
); ++index
)
874 if (fallbackWindows
[index
].origin
== windowID
)
875 return fallbackWindows
[index
].target
;
877 // for addon windows use WINDOW_ADDON_START because id is dynamic
878 if (windowID
> WINDOW_ADDON_START
&& windowID
<= WINDOW_ADDON_END
)
879 return WINDOW_ADDON_START
;
884 CAction
CButtonTranslator::GetAction(int window
, const CKey
&key
, bool fallback
)
886 std::string strAction
;
887 // try to get the action from the current window
888 int actionID
= GetActionCode(window
, key
, strAction
);
889 // if it's invalid, try to get it from the global map
890 if (actionID
== 0 && fallback
)
892 int fallbackWindow
= GetFallbackWindow(window
);
893 if (fallbackWindow
> -1)
894 actionID
= GetActionCode(fallbackWindow
, key
, strAction
);
895 // still no valid action? use global map
897 actionID
= GetActionCode( -1, key
, strAction
);
899 // Now fill our action structure
900 CAction
action(actionID
, strAction
, key
);
904 CAction
CButtonTranslator::GetGlobalAction(const CKey
&key
)
906 return GetAction(-1, key
, true);
909 bool CButtonTranslator::HasLonpressMapping(int window
, const CKey
&key
)
911 std::map
<int, buttonMap
>::const_iterator it
= m_translatorMap
.find(window
);
912 if (it
!= m_translatorMap
.end())
914 uint32_t code
= key
.GetButtonCode();
915 code
|= CKey::MODIFIER_LONG
;
916 buttonMap::const_iterator it2
= (*it
).second
.find(code
);
918 if (it2
!= (*it
).second
.end())
922 // Some buttoncodes changed in Hardy
923 if ((code
& KEY_VKEY
) == KEY_VKEY
&& (code
& 0x0F00))
926 it2
= (*it
).second
.find(code
);
927 if (it2
!= (*it
).second
.end())
933 // no key mapping found for the current window do the fallback handling
936 // first check if we have a fallback for the window
937 int fallbackWindow
= GetFallbackWindow(window
);
938 if (fallbackWindow
> -1 && HasLonpressMapping(fallbackWindow
, key
))
941 // fallback to default section
942 return HasLonpressMapping(-1, key
);
948 int CButtonTranslator::GetActionCode(int window
, const CKey
&key
, std::string
&strAction
) const
950 uint32_t code
= key
.GetButtonCode();
952 std::map
<int, buttonMap
>::const_iterator it
= m_translatorMap
.find(window
);
953 if (it
== m_translatorMap
.end())
955 buttonMap::const_iterator it2
= (*it
).second
.find(code
);
957 if (it2
== (*it
).second
.end() && code
& CKey::MODIFIER_LONG
) // If long action not found, try short one
959 code
&= ~CKey::MODIFIER_LONG
;
960 it2
= (*it
).second
.find(code
);
962 if (it2
!= (*it
).second
.end())
964 action
= (*it2
).second
.id
;
965 strAction
= (*it2
).second
.strID
;
968 // Some buttoncodes changed in Hardy
969 if (action
== 0 && (code
& KEY_VKEY
) == KEY_VKEY
&& (code
& 0x0F00))
971 CLog::Log(LOGDEBUG
, "%s: Trying Hardy keycode for %#04x", __FUNCTION__
, code
);
973 it2
= (*it
).second
.find(code
);
974 if (it2
!= (*it
).second
.end())
976 action
= (*it2
).second
.id
;
977 strAction
= (*it2
).second
.strID
;
984 void CButtonTranslator::MapAction(uint32_t buttonCode
, const char *szAction
, buttonMap
&map
)
986 int action
= ACTION_NONE
;
987 if (!TranslateActionString(szAction
, action
) || !buttonCode
)
988 return; // no valid action, or an invalid buttoncode
990 // have a valid action, and a valid button - map it.
991 // check to see if we've already got this (button,action) pair defined
992 buttonMap::iterator it
= map
.find(buttonCode
);
993 if (it
== map
.end() || (*it
).second
.id
!= action
|| (*it
).second
.strID
!= szAction
)
995 // NOTE: This multimap is only being used as a normal map at this point (no support
996 // for multiple actions per key)
999 CButtonAction button
;
1001 button
.strID
= szAction
;
1002 map
.insert(std::pair
<uint32_t, CButtonAction
>(buttonCode
, button
));
1006 void CButtonTranslator::MapCustomControllerActions(int windowID
, TiXmlNode
*pCustomController
)
1008 CustomControllerButtonMap buttonMap
;
1009 std::string controllerName
;
1011 TiXmlElement
*pController
= pCustomController
->ToElement();
1014 // transform loose name to new family, including altnames
1015 if(pController
->Attribute("name"))
1017 controllerName
= pController
->Attribute("name");
1021 CLog::Log(LOGERROR
, "Missing attribute \"name\" for tag \"customcontroller\"");
1027 TiXmlElement
*pButton
= pCustomController
->FirstChildElement();
1032 if (!pButton
->NoChildren())
1033 action
= pButton
->FirstChild()->ValueStr();
1035 if ((pButton
->QueryIntAttribute("id", &id
) == TIXML_SUCCESS
) && id
>= 0)
1037 buttonMap
[id
] = action
;
1040 CLog::Log(LOGERROR
, "Error reading customController map element, Invalid id: %d", id
);
1042 pButton
= pButton
->NextSiblingElement();
1045 // add/overwrite button with mapped actions
1046 for (auto button
: buttonMap
)
1047 m_customControllersMap
[controllerName
][windowID
][button
.first
] = button
.second
;
1050 bool CButtonTranslator::HasDeviceType(TiXmlNode
*pWindow
, std::string type
)
1052 return pWindow
->FirstChild(type
) != NULL
;
1055 void CButtonTranslator::MapWindowActions(TiXmlNode
*pWindow
, int windowID
)
1057 if (!pWindow
|| windowID
== WINDOW_INVALID
)
1062 const char* types
[] = {"gamepad", "remote", "universalremote", "keyboard", "mouse", "appcommand", "joystick", NULL
};
1063 for (int i
= 0; types
[i
]; ++i
)
1065 std::string
type(types
[i
]);
1066 if (HasDeviceType(pWindow
, type
))
1069 std::map
<int, buttonMap
>::iterator it
= m_translatorMap
.find(windowID
);
1070 if (it
!= m_translatorMap
.end())
1073 m_translatorMap
.erase(it
);
1076 pDevice
= pWindow
->FirstChild(type
);
1078 TiXmlElement
*pButton
= pDevice
->FirstChildElement();
1082 uint32_t buttonCode
=0;
1083 if (type
== "gamepad")
1084 buttonCode
= TranslateGamepadString(pButton
->Value());
1085 else if (type
== "remote")
1086 buttonCode
= TranslateRemoteString(pButton
->Value());
1087 else if (type
== "universalremote")
1088 buttonCode
= TranslateUniversalRemoteString(pButton
->Value());
1089 else if (type
== "keyboard")
1090 buttonCode
= TranslateKeyboardButton(pButton
);
1091 else if (type
== "mouse")
1092 buttonCode
= TranslateMouseCommand(pButton
);
1093 else if (type
== "appcommand")
1094 buttonCode
= TranslateAppCommand(pButton
->Value());
1095 else if (type
== "joystick")
1096 buttonCode
= TranslateJoystickString(pButton
->Value());
1100 if (pButton
->FirstChild() && pButton
->FirstChild()->Value()[0])
1101 MapAction(buttonCode
, pButton
->FirstChild()->Value(), map
);
1104 buttonMap::iterator it
= map
.find(buttonCode
);
1105 while (it
!= map
.end())
1108 it
= map
.find(buttonCode
);
1112 pButton
= pButton
->NextSiblingElement();
1115 // add our map to our table
1117 m_translatorMap
.insert(std::pair
<int, buttonMap
>( windowID
, map
));
1121 if ((pDevice
= pWindow
->FirstChild("touch")) != NULL
)
1123 // map touch actions
1126 MapTouchActions(windowID
, pDevice
);
1127 pDevice
= pDevice
->NextSibling("touch");
1131 if ((pDevice
= pWindow
->FirstChild("customcontroller")) != NULL
)
1133 // map custom controller actions
1136 MapCustomControllerActions(windowID
, pDevice
);
1137 pDevice
= pDevice
->NextSibling("customcontroller");
1143 bool CButtonTranslator::TranslateActionString(const char *szAction
, int &action
)
1145 action
= ACTION_NONE
;
1146 std::string strAction
= szAction
;
1147 StringUtils::ToLower(strAction
);
1148 if (CBuiltins::GetInstance().HasCommand(strAction
))
1149 action
= ACTION_BUILT_IN_FUNCTION
;
1151 for (unsigned int index
=0;index
< ARRAY_SIZE(actions
);++index
)
1153 if (strAction
== actions
[index
].name
)
1155 action
= actions
[index
].action
;
1160 if (action
== ACTION_NONE
)
1162 CLog::Log(LOGERROR
, "Keymapping error: no such action '%s' defined", strAction
.c_str());
1169 std::string
CButtonTranslator::TranslateWindow(int windowID
)
1171 for (unsigned int index
= 0; index
< ARRAY_SIZE(windows
); ++index
)
1173 if (windows
[index
].action
== windowID
)
1174 return windows
[index
].name
;
1179 int CButtonTranslator::TranslateWindow(const std::string
&window
)
1181 std::string
strWindow(window
);
1182 if (strWindow
.empty())
1183 return WINDOW_INVALID
;
1184 StringUtils::ToLower(strWindow
);
1186 if (StringUtils::EndsWith(strWindow
, ".xml"))
1187 strWindow
= strWindow
.substr(0, strWindow
.size() - 4);
1189 // window12345, for custom window to be keymapped
1190 if (strWindow
.length() > 6 && StringUtils::StartsWithNoCase(strWindow
, "window"))
1191 strWindow
= strWindow
.substr(6);
1192 if (StringUtils::StartsWithNoCase(strWindow
, "my")) // drop "my" prefix
1193 strWindow
= strWindow
.substr(2);
1194 if (StringUtils::IsNaturalNumber(strWindow
))
1196 // allow a full window id or a delta id
1197 int iWindow
= atoi(strWindow
.c_str());
1198 if (iWindow
> WINDOW_INVALID
)
1200 return WINDOW_HOME
+ iWindow
;
1203 // run through the window structure
1204 for (unsigned int index
= 0; index
< ARRAY_SIZE(windows
); ++index
)
1206 if (strWindow
== windows
[index
].name
)
1207 return windows
[index
].action
;
1210 CLog::Log(LOGERROR
, "Window Translator: Can't find window %s", strWindow
.c_str());
1211 return WINDOW_INVALID
;
1214 uint32_t CButtonTranslator::TranslateGamepadString(const char *szButton
)
1218 uint32_t buttonCode
= 0;
1219 std::string strButton
= szButton
;
1220 StringUtils::ToLower(strButton
);
1221 if (strButton
== "a") buttonCode
= KEY_BUTTON_A
;
1222 else if (strButton
== "b") buttonCode
= KEY_BUTTON_B
;
1223 else if (strButton
== "x") buttonCode
= KEY_BUTTON_X
;
1224 else if (strButton
== "y") buttonCode
= KEY_BUTTON_Y
;
1225 else if (strButton
== "white") buttonCode
= KEY_BUTTON_WHITE
;
1226 else if (strButton
== "black") buttonCode
= KEY_BUTTON_BLACK
;
1227 else if (strButton
== "start") buttonCode
= KEY_BUTTON_START
;
1228 else if (strButton
== "back") buttonCode
= KEY_BUTTON_BACK
;
1229 else if (strButton
== "leftthumbbutton") buttonCode
= KEY_BUTTON_LEFT_THUMB_BUTTON
;
1230 else if (strButton
== "rightthumbbutton") buttonCode
= KEY_BUTTON_RIGHT_THUMB_BUTTON
;
1231 else if (strButton
== "leftthumbstick") buttonCode
= KEY_BUTTON_LEFT_THUMB_STICK
;
1232 else if (strButton
== "leftthumbstickup") buttonCode
= KEY_BUTTON_LEFT_THUMB_STICK_UP
;
1233 else if (strButton
== "leftthumbstickdown") buttonCode
= KEY_BUTTON_LEFT_THUMB_STICK_DOWN
;
1234 else if (strButton
== "leftthumbstickleft") buttonCode
= KEY_BUTTON_LEFT_THUMB_STICK_LEFT
;
1235 else if (strButton
== "leftthumbstickright") buttonCode
= KEY_BUTTON_LEFT_THUMB_STICK_RIGHT
;
1236 else if (strButton
== "rightthumbstick") buttonCode
= KEY_BUTTON_RIGHT_THUMB_STICK
;
1237 else if (strButton
== "rightthumbstickup") buttonCode
= KEY_BUTTON_RIGHT_THUMB_STICK_UP
;
1238 else if (strButton
== "rightthumbstickdown") buttonCode
= KEY_BUTTON_RIGHT_THUMB_STICK_DOWN
;
1239 else if (strButton
== "rightthumbstickleft") buttonCode
= KEY_BUTTON_RIGHT_THUMB_STICK_LEFT
;
1240 else if (strButton
== "rightthumbstickright") buttonCode
= KEY_BUTTON_RIGHT_THUMB_STICK_RIGHT
;
1241 else if (strButton
== "lefttrigger") buttonCode
= KEY_BUTTON_LEFT_TRIGGER
;
1242 else if (strButton
== "righttrigger") buttonCode
= KEY_BUTTON_RIGHT_TRIGGER
;
1243 else if (strButton
== "leftanalogtrigger") buttonCode
= KEY_BUTTON_LEFT_ANALOG_TRIGGER
;
1244 else if (strButton
== "rightanalogtrigger") buttonCode
= KEY_BUTTON_RIGHT_ANALOG_TRIGGER
;
1245 else if (strButton
== "dpadleft") buttonCode
= KEY_BUTTON_DPAD_LEFT
;
1246 else if (strButton
== "dpadright") buttonCode
= KEY_BUTTON_DPAD_RIGHT
;
1247 else if (strButton
== "dpadup") buttonCode
= KEY_BUTTON_DPAD_UP
;
1248 else if (strButton
== "dpaddown") buttonCode
= KEY_BUTTON_DPAD_DOWN
;
1249 else CLog::Log(LOGERROR
, "Gamepad Translator: Can't find button %s", strButton
.c_str());
1253 uint32_t CButtonTranslator::TranslateRemoteString(const char *szButton
)
1257 uint32_t buttonCode
= 0;
1258 std::string strButton
= szButton
;
1259 StringUtils::ToLower(strButton
);
1260 if (strButton
== "left") buttonCode
= XINPUT_IR_REMOTE_LEFT
;
1261 else if (strButton
== "right") buttonCode
= XINPUT_IR_REMOTE_RIGHT
;
1262 else if (strButton
== "up") buttonCode
= XINPUT_IR_REMOTE_UP
;
1263 else if (strButton
== "down") buttonCode
= XINPUT_IR_REMOTE_DOWN
;
1264 else if (strButton
== "select") buttonCode
= XINPUT_IR_REMOTE_SELECT
;
1265 else if (strButton
== "back") buttonCode
= XINPUT_IR_REMOTE_BACK
;
1266 else if (strButton
== "menu") buttonCode
= XINPUT_IR_REMOTE_MENU
;
1267 else if (strButton
== "info") buttonCode
= XINPUT_IR_REMOTE_INFO
;
1268 else if (strButton
== "display") buttonCode
= XINPUT_IR_REMOTE_DISPLAY
;
1269 else if (strButton
== "title") buttonCode
= XINPUT_IR_REMOTE_TITLE
;
1270 else if (strButton
== "play") buttonCode
= XINPUT_IR_REMOTE_PLAY
;
1271 else if (strButton
== "pause") buttonCode
= XINPUT_IR_REMOTE_PAUSE
;
1272 else if (strButton
== "reverse") buttonCode
= XINPUT_IR_REMOTE_REVERSE
;
1273 else if (strButton
== "forward") buttonCode
= XINPUT_IR_REMOTE_FORWARD
;
1274 else if (strButton
== "skipplus") buttonCode
= XINPUT_IR_REMOTE_SKIP_PLUS
;
1275 else if (strButton
== "skipminus") buttonCode
= XINPUT_IR_REMOTE_SKIP_MINUS
;
1276 else if (strButton
== "stop") buttonCode
= XINPUT_IR_REMOTE_STOP
;
1277 else if (strButton
== "zero") buttonCode
= XINPUT_IR_REMOTE_0
;
1278 else if (strButton
== "one") buttonCode
= XINPUT_IR_REMOTE_1
;
1279 else if (strButton
== "two") buttonCode
= XINPUT_IR_REMOTE_2
;
1280 else if (strButton
== "three") buttonCode
= XINPUT_IR_REMOTE_3
;
1281 else if (strButton
== "four") buttonCode
= XINPUT_IR_REMOTE_4
;
1282 else if (strButton
== "five") buttonCode
= XINPUT_IR_REMOTE_5
;
1283 else if (strButton
== "six") buttonCode
= XINPUT_IR_REMOTE_6
;
1284 else if (strButton
== "seven") buttonCode
= XINPUT_IR_REMOTE_7
;
1285 else if (strButton
== "eight") buttonCode
= XINPUT_IR_REMOTE_8
;
1286 else if (strButton
== "nine") buttonCode
= XINPUT_IR_REMOTE_9
;
1287 // additional keys from the media center extender for xbox remote
1288 else if (strButton
== "power") buttonCode
= XINPUT_IR_REMOTE_POWER
;
1289 else if (strButton
== "mytv") buttonCode
= XINPUT_IR_REMOTE_MY_TV
;
1290 else if (strButton
== "mymusic") buttonCode
= XINPUT_IR_REMOTE_MY_MUSIC
;
1291 else if (strButton
== "mypictures") buttonCode
= XINPUT_IR_REMOTE_MY_PICTURES
;
1292 else if (strButton
== "myvideo") buttonCode
= XINPUT_IR_REMOTE_MY_VIDEOS
;
1293 else if (strButton
== "record") buttonCode
= XINPUT_IR_REMOTE_RECORD
;
1294 else if (strButton
== "start") buttonCode
= XINPUT_IR_REMOTE_START
;
1295 else if (strButton
== "volumeplus") buttonCode
= XINPUT_IR_REMOTE_VOLUME_PLUS
;
1296 else if (strButton
== "volumeminus") buttonCode
= XINPUT_IR_REMOTE_VOLUME_MINUS
;
1297 else if (strButton
== "channelplus") buttonCode
= XINPUT_IR_REMOTE_CHANNEL_PLUS
;
1298 else if (strButton
== "channelminus") buttonCode
= XINPUT_IR_REMOTE_CHANNEL_MINUS
;
1299 else if (strButton
== "pageplus") buttonCode
= XINPUT_IR_REMOTE_CHANNEL_PLUS
;
1300 else if (strButton
== "pageminus") buttonCode
= XINPUT_IR_REMOTE_CHANNEL_MINUS
;
1301 else if (strButton
== "mute") buttonCode
= XINPUT_IR_REMOTE_MUTE
;
1302 else if (strButton
== "recordedtv") buttonCode
= XINPUT_IR_REMOTE_RECORDED_TV
;
1303 else if (strButton
== "guide") buttonCode
= XINPUT_IR_REMOTE_GUIDE
;
1304 else if (strButton
== "livetv") buttonCode
= XINPUT_IR_REMOTE_LIVE_TV
;
1305 else if (strButton
== "liveradio") buttonCode
= XINPUT_IR_REMOTE_LIVE_RADIO
;
1306 else if (strButton
== "epgsearch") buttonCode
= XINPUT_IR_REMOTE_EPG_SEARCH
;
1307 else if (strButton
== "star") buttonCode
= XINPUT_IR_REMOTE_STAR
;
1308 else if (strButton
== "hash") buttonCode
= XINPUT_IR_REMOTE_HASH
;
1309 else if (strButton
== "clear") buttonCode
= XINPUT_IR_REMOTE_CLEAR
;
1310 else if (strButton
== "enter") buttonCode
= XINPUT_IR_REMOTE_ENTER
;
1311 else if (strButton
== "xbox") buttonCode
= XINPUT_IR_REMOTE_DISPLAY
; // same as display
1312 else if (strButton
== "playlist") buttonCode
= XINPUT_IR_REMOTE_PLAYLIST
;
1313 else if (strButton
== "teletext") buttonCode
= XINPUT_IR_REMOTE_TELETEXT
;
1314 else if (strButton
== "red") buttonCode
= XINPUT_IR_REMOTE_RED
;
1315 else if (strButton
== "green") buttonCode
= XINPUT_IR_REMOTE_GREEN
;
1316 else if (strButton
== "yellow") buttonCode
= XINPUT_IR_REMOTE_YELLOW
;
1317 else if (strButton
== "blue") buttonCode
= XINPUT_IR_REMOTE_BLUE
;
1318 else if (strButton
== "subtitle") buttonCode
= XINPUT_IR_REMOTE_SUBTITLE
;
1319 else if (strButton
== "language") buttonCode
= XINPUT_IR_REMOTE_LANGUAGE
;
1320 else if (strButton
== "eject") buttonCode
= XINPUT_IR_REMOTE_EJECT
;
1321 else if (strButton
== "contentsmenu") buttonCode
= XINPUT_IR_REMOTE_CONTENTS_MENU
;
1322 else if (strButton
== "rootmenu") buttonCode
= XINPUT_IR_REMOTE_ROOT_MENU
;
1323 else if (strButton
== "topmenu") buttonCode
= XINPUT_IR_REMOTE_TOP_MENU
;
1324 else if (strButton
== "dvdmenu") buttonCode
= XINPUT_IR_REMOTE_DVD_MENU
;
1325 else if (strButton
== "print") buttonCode
= XINPUT_IR_REMOTE_PRINT
;
1326 else CLog::Log(LOGERROR
, "Remote Translator: Can't find button %s", strButton
.c_str());
1330 uint32_t CButtonTranslator::TranslateUniversalRemoteString(const char *szButton
)
1332 if (!szButton
|| strlen(szButton
) < 4 || strnicmp(szButton
, "obc", 3))
1334 const char *szCode
= szButton
+ 3;
1335 // Button Code is 255 - OBC (Original Button Code) of the button
1336 uint32_t buttonCode
= 255 - atol(szCode
);
1337 if (buttonCode
> 255)
1342 uint32_t CButtonTranslator::TranslateKeyboardString(const char *szButton
)
1344 uint32_t buttonCode
= 0;
1345 XBMCKEYTABLE keytable
;
1347 // Look up the key name
1348 if (KeyTableLookupName(szButton
, &keytable
))
1350 buttonCode
= keytable
.vkey
;
1353 // The lookup failed i.e. the key name wasn't found
1356 CLog::Log(LOGERROR
, "Keyboard Translator: Can't find button %s", szButton
);
1359 buttonCode
|= KEY_VKEY
;
1364 uint32_t CButtonTranslator::TranslateKeyboardButton(TiXmlElement
*pButton
)
1366 uint32_t button_id
= 0;
1367 const char *szButton
= pButton
->Value();
1371 const std::string strKey
= szButton
;
1372 if (strKey
== "key")
1375 if (pButton
->QueryValueAttribute("id", &strID
) == TIXML_SUCCESS
)
1377 const char *str
= strID
.c_str();
1379 long int id
= strtol(str
, &endptr
, 0);
1380 if (endptr
- str
!= (int)strlen(str
) || id
<= 0 || id
> 0x00FFFFFF)
1381 CLog::Log(LOGDEBUG
, "%s - invalid key id %s", __FUNCTION__
, strID
.c_str());
1383 button_id
= (uint32_t) id
;
1386 CLog::Log(LOGERROR
, "Keyboard Translator: `key' button has no id");
1389 button_id
= TranslateKeyboardString(szButton
);
1391 // Process the ctrl/shift/alt modifiers
1393 if (pButton
->QueryValueAttribute("mod", &strMod
) == TIXML_SUCCESS
)
1395 StringUtils::ToLower(strMod
);
1397 std::vector
<std::string
> modArray
= StringUtils::Split(strMod
, ",");
1398 for (std::vector
<std::string
>::const_iterator i
= modArray
.begin(); i
!= modArray
.end(); ++i
)
1400 std::string substr
= *i
;
1401 StringUtils::Trim(substr
);
1403 if (substr
== "ctrl" || substr
== "control")
1404 button_id
|= CKey::MODIFIER_CTRL
;
1405 else if (substr
== "shift")
1406 button_id
|= CKey::MODIFIER_SHIFT
;
1407 else if (substr
== "alt")
1408 button_id
|= CKey::MODIFIER_ALT
;
1409 else if (substr
== "super" || substr
== "win")
1410 button_id
|= CKey::MODIFIER_SUPER
;
1411 else if (substr
== "meta" || substr
== "cmd")
1412 button_id
|= CKey::MODIFIER_META
;
1413 else if (substr
== "longpress")
1414 button_id
|= CKey::MODIFIER_LONG
;
1416 CLog::Log(LOGERROR
, "Keyboard Translator: Unknown key modifier %s in %s", substr
.c_str(), strMod
.c_str());
1423 uint32_t CButtonTranslator::TranslateAppCommand(const char *szButton
)
1425 #ifdef TARGET_WINDOWS
1426 std::string strAppCommand
= szButton
;
1427 StringUtils::ToLower(strAppCommand
);
1429 for (int i
= 0; i
< ARRAY_SIZE(appcommands
); i
++)
1430 if (strAppCommand
== appcommands
[i
].name
)
1431 return appcommands
[i
].action
| KEY_APPCOMMAND
;
1433 CLog::Log(LOGERROR
, "%s: Can't find appcommand %s", __FUNCTION__
, szButton
);
1439 uint32_t CButtonTranslator::TranslateMouseCommand(TiXmlElement
*pButton
)
1441 uint32_t buttonId
= 0;
1445 std::string szKey
= pButton
->ValueStr();
1448 StringUtils::ToLower(szKey
);
1449 for (unsigned int i
= 0; i
< ARRAY_SIZE(mousekeys
); i
++)
1451 if (szKey
== mousekeys
[i
].name
)
1453 buttonId
= mousekeys
[i
].action
;
1459 CLog::Log(LOGERROR
, "Unknown mouse action (%s), skipping", pButton
->Value());
1464 if ((pButton
->QueryIntAttribute("id", &id
) == TIXML_SUCCESS
) && id
>=0 && id
<MOUSE_MAX_BUTTON
)
1475 void CButtonTranslator::Clear()
1477 m_translatorMap
.clear();
1478 #if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
1479 ClearLircButtonMapEntries();
1480 lircRemotesMap
.clear();
1483 m_customControllersMap
.clear();
1488 uint32_t CButtonTranslator::TranslateTouchCommand(TiXmlElement
*pButton
, CButtonAction
&action
)
1490 const char *szButton
= pButton
->Value();
1491 if (szButton
== NULL
|| pButton
->FirstChild() == NULL
)
1494 const char *szAction
= pButton
->FirstChild()->Value();
1495 if (szAction
== NULL
)
1498 std::string strTouchCommand
= szButton
;
1499 StringUtils::ToLower(strTouchCommand
);
1501 const char *attrVal
= pButton
->Attribute("direction");
1502 if (attrVal
!= NULL
)
1503 strTouchCommand
+= attrVal
;
1505 uint32_t actionId
= ACTION_NONE
;
1506 for (unsigned int i
= 0; i
< ARRAY_SIZE(touchcommands
); i
++)
1508 if (strTouchCommand
== touchcommands
[i
].name
)
1510 actionId
= touchcommands
[i
].action
;
1515 if (actionId
<= ACTION_NONE
)
1517 CLog::Log(LOGERROR
, "%s: Can't find touch command %s", __FUNCTION__
, szButton
);
1521 attrVal
= pButton
->Attribute("pointers");
1522 if (attrVal
!= NULL
)
1524 int pointers
= (int)strtol(attrVal
, NULL
, 0);
1526 actionId
+= pointers
- 1;
1529 action
.strID
= szAction
;
1530 if (!TranslateActionString(szAction
, action
.id
) || action
.id
<= ACTION_NONE
)
1533 return actionId
| KEY_TOUCH
;
1536 void CButtonTranslator::MapTouchActions(int windowID
, TiXmlNode
*pTouch
)
1542 // check if there already is a touch map for the window ID
1543 std::map
<int, buttonMap
>::iterator it
= m_touchMap
.find(windowID
);
1544 if (it
!= m_touchMap
.end())
1546 // get the existing touch map and remove it from the window mapping
1547 // as it will be inserted later on
1549 m_touchMap
.erase(it
);
1552 uint32_t actionId
= 0;
1553 TiXmlElement
*pTouchElem
= pTouch
->ToElement();
1554 if (pTouchElem
== NULL
)
1557 TiXmlElement
*pButton
= pTouchElem
->FirstChildElement();
1558 while (pButton
!= NULL
)
1560 CButtonAction action
;
1561 actionId
= TranslateTouchCommand(pButton
, action
);
1564 // check if there already is a mapping for the parsed action
1565 // and remove it if necessary
1566 buttonMap::iterator actionIt
= map
.find(actionId
);
1567 if (actionIt
!= map
.end())
1568 map
.erase(actionIt
);
1570 map
.insert(std::make_pair(actionId
, action
));
1573 pButton
= pButton
->NextSiblingElement();
1576 // add the modified touch map with the window ID
1578 m_touchMap
.insert(std::pair
<int, buttonMap
>(windowID
, map
));
1581 int CButtonTranslator::GetTouchActionCode(int window
, int action
, std::string
&actionString
)
1583 std::map
<int, buttonMap
>::const_iterator windowIt
= m_touchMap
.find(window
);
1584 if (windowIt
== m_touchMap
.end())
1587 buttonMap::const_iterator touchIt
= windowIt
->second
.find(action
);
1588 if (touchIt
== windowIt
->second
.end())
1591 actionString
= touchIt
->second
.strID
;
1592 return touchIt
->second
.id
;
1595 uint32_t CButtonTranslator::TranslateJoystickString(const char *szButton
)
1599 uint32_t buttonCode
= 0;
1600 std::string strButton
= szButton
;
1601 StringUtils::ToLower(strButton
);
1603 if (strButton
== "a") buttonCode
= KEY_JOYSTICK_BUTTON_A
;
1604 else if (strButton
== "b") buttonCode
= KEY_JOYSTICK_BUTTON_B
;
1605 else if (strButton
== "x") buttonCode
= KEY_JOYSTICK_BUTTON_X
;
1606 else if (strButton
== "y") buttonCode
= KEY_JOYSTICK_BUTTON_Y
;
1607 else if (strButton
== "start") buttonCode
= KEY_JOYSTICK_BUTTON_START
;
1608 else if (strButton
== "back") buttonCode
= KEY_JOYSTICK_BUTTON_BACK
;
1609 else if (strButton
== "left") buttonCode
= KEY_JOYSTICK_BUTTON_DPAD_LEFT
;
1610 else if (strButton
== "right") buttonCode
= KEY_JOYSTICK_BUTTON_DPAD_RIGHT
;
1611 else if (strButton
== "up") buttonCode
= KEY_JOYSTICK_BUTTON_DPAD_UP
;
1612 else if (strButton
== "down") buttonCode
= KEY_JOYSTICK_BUTTON_DPAD_DOWN
;
1613 else if (strButton
== "leftthumb") buttonCode
= KEY_JOYSTICK_BUTTON_LEFT_STICK_BUTTON
;
1614 else if (strButton
== "rightthumb") buttonCode
= KEY_JOYSTICK_BUTTON_RIGHT_STICK_BUTTON
;
1615 else if (strButton
== "leftstickup") buttonCode
= KEY_JOYSTICK_BUTTON_LEFT_THUMB_STICK_UP
;
1616 else if (strButton
== "leftstickdown") buttonCode
= KEY_JOYSTICK_BUTTON_LEFT_THUMB_STICK_DOWN
;
1617 else if (strButton
== "leftstickleft") buttonCode
= KEY_JOYSTICK_BUTTON_LEFT_THUMB_STICK_LEFT
;
1618 else if (strButton
== "leftstickright") buttonCode
= KEY_JOYSTICK_BUTTON_LEFT_THUMB_STICK_RIGHT
;
1619 else if (strButton
== "rightstickup") buttonCode
= KEY_JOYSTICK_BUTTON_RIGHT_THUMB_STICK_UP
;
1620 else if (strButton
== "rightstickdown") buttonCode
= KEY_JOYSTICK_BUTTON_RIGHT_THUMB_STICK_DOWN
;
1621 else if (strButton
== "rightstickleft") buttonCode
= KEY_JOYSTICK_BUTTON_RIGHT_THUMB_STICK_LEFT
;
1622 else if (strButton
== "rightstickright") buttonCode
= KEY_JOYSTICK_BUTTON_RIGHT_THUMB_STICK_RIGHT
;
1623 else if (strButton
== "lefttrigger") buttonCode
= KEY_JOYSTICK_BUTTON_LEFT_TRIGGER
;
1624 else if (strButton
== "righttrigger") buttonCode
= KEY_JOYSTICK_BUTTON_RIGHT_TRIGGER
;
1625 else if (strButton
== "leftbumper") buttonCode
= KEY_JOYSTICK_BUTTON_LEFT_SHOULDER
;
1626 else if (strButton
== "rightbumper") buttonCode
= KEY_JOYSTICK_BUTTON_RIGHT_SHOULDER
;
1627 else if (strButton
== "guide") buttonCode
= KEY_JOYSTICK_BUTTON_GUIDE
;
1628 else CLog::Log(LOGERROR
, "Joystick Translator: Can't find button %s", strButton
.c_str());