2 * Copyright (C) 2005-2013 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 XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
22 #include "interfaces/Builtins.h"
23 #include "ButtonTranslator.h"
24 #include "profiles/ProfilesManager.h"
25 #include "utils/URIUtils.h"
26 #include "guilib/Key.h"
27 #include "guilib/WindowIDs.h"
28 #include "input/XBMC_keysym.h"
29 #include "input/XBMC_keytable.h"
30 #include "filesystem/File.h"
31 #include "filesystem/Directory.h"
33 #include "utils/StringUtils.h"
34 #include "utils/log.h"
35 #include "utils/XBMCTinyXML.h"
36 #include "XBIRRemote.h"
38 #if defined(TARGET_WINDOWS)
39 #include "input/windows/WINJoystick.h"
40 #elif defined(HAS_SDL_JOYSTICK) || defined(HAS_EVENT_SERVER)
41 #include "SDLJoystick.h"
44 #define JOYSTICK_DEFAULT_MAP "_xbmc_"
47 using namespace XFILE
;
61 static const ActionMapping actions
[] =
63 {"left" , ACTION_MOVE_LEFT
},
64 {"right" , ACTION_MOVE_RIGHT
},
65 {"up" , ACTION_MOVE_UP
},
66 {"down" , ACTION_MOVE_DOWN
},
67 {"pageup" , ACTION_PAGE_UP
},
68 {"pagedown" , ACTION_PAGE_DOWN
},
69 {"select" , ACTION_SELECT_ITEM
},
70 {"highlight" , ACTION_HIGHLIGHT_ITEM
},
71 {"parentdir" , ACTION_NAV_BACK
}, // backward compatibility
72 {"parentfolder" , ACTION_PARENT_DIR
},
73 {"back" , ACTION_NAV_BACK
},
74 {"previousmenu" , ACTION_PREVIOUS_MENU
},
75 {"info" , ACTION_SHOW_INFO
},
76 {"pause" , ACTION_PAUSE
},
77 {"stop" , ACTION_STOP
},
78 {"skipnext" , ACTION_NEXT_ITEM
},
79 {"skipprevious" , ACTION_PREV_ITEM
},
80 {"fullscreen" , ACTION_SHOW_GUI
},
81 {"aspectratio" , ACTION_ASPECT_RATIO
},
82 {"stepforward" , ACTION_STEP_FORWARD
},
83 {"stepback" , ACTION_STEP_BACK
},
84 {"bigstepforward" , ACTION_BIG_STEP_FORWARD
},
85 {"bigstepback" , ACTION_BIG_STEP_BACK
},
86 {"chapterorbigstepforward", ACTION_CHAPTER_OR_BIG_STEP_FORWARD
},
87 {"chapterorbigstepback" , ACTION_CHAPTER_OR_BIG_STEP_BACK
},
88 {"osd" , ACTION_SHOW_OSD
},
89 {"showsubtitles" , ACTION_SHOW_SUBTITLES
},
90 {"nextsubtitle" , ACTION_NEXT_SUBTITLE
},
91 {"codecinfo" , ACTION_SHOW_CODEC
},
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 {"rotate" , ACTION_ROTATE_PICTURE_CW
},
112 {"rotateccw" , ACTION_ROTATE_PICTURE_CCW
},
113 {"close" , ACTION_NAV_BACK
}, // backwards compatibility
114 {"subtitledelayminus", ACTION_SUBTITLE_DELAY_MIN
},
115 {"subtitledelay" , ACTION_SUBTITLE_DELAY
},
116 {"subtitledelayplus" , ACTION_SUBTITLE_DELAY_PLUS
},
117 {"audiodelayminus" , ACTION_AUDIO_DELAY_MIN
},
118 {"audiodelay" , ACTION_AUDIO_DELAY
},
119 {"audiodelayplus" , ACTION_AUDIO_DELAY_PLUS
},
120 {"subtitleshiftup" , ACTION_SUBTITLE_VSHIFT_UP
},
121 {"subtitleshiftdown" , ACTION_SUBTITLE_VSHIFT_DOWN
},
122 {"subtitlealign" , ACTION_SUBTITLE_ALIGN
},
123 {"audionextlanguage" , ACTION_AUDIO_NEXT_LANGUAGE
},
124 {"verticalshiftup" , ACTION_VSHIFT_UP
},
125 {"verticalshiftdown" , ACTION_VSHIFT_DOWN
},
126 {"nextresolution" , ACTION_CHANGE_RESOLUTION
},
127 {"audiotoggledigital", ACTION_TOGGLE_DIGITAL_ANALOG
},
128 {"number0" , REMOTE_0
},
129 {"number1" , REMOTE_1
},
130 {"number2" , REMOTE_2
},
131 {"number3" , REMOTE_3
},
132 {"number4" , REMOTE_4
},
133 {"number5" , REMOTE_5
},
134 {"number6" , REMOTE_6
},
135 {"number7" , REMOTE_7
},
136 {"number8" , REMOTE_8
},
137 {"number9" , REMOTE_9
},
138 {"osdleft" , ACTION_OSD_SHOW_LEFT
},
139 {"osdright" , ACTION_OSD_SHOW_RIGHT
},
140 {"osdup" , ACTION_OSD_SHOW_UP
},
141 {"osddown" , ACTION_OSD_SHOW_DOWN
},
142 {"osdselect" , ACTION_OSD_SHOW_SELECT
},
143 {"osdvalueplus" , ACTION_OSD_SHOW_VALUE_PLUS
},
144 {"osdvalueminus" , ACTION_OSD_SHOW_VALUE_MIN
},
145 {"smallstepback" , ACTION_SMALL_STEP_BACK
},
146 {"fastforward" , ACTION_PLAYER_FORWARD
},
147 {"rewind" , ACTION_PLAYER_REWIND
},
148 {"play" , ACTION_PLAYER_PLAY
},
149 {"playpause" , ACTION_PLAYER_PLAYPAUSE
},
150 {"switchplayer" , ACTION_SWITCH_PLAYER
},
151 {"delete" , ACTION_DELETE_ITEM
},
152 {"copy" , ACTION_COPY_ITEM
},
153 {"move" , ACTION_MOVE_ITEM
},
154 {"mplayerosd" , ACTION_SHOW_MPLAYER_OSD
},
155 {"hidesubmenu" , ACTION_OSD_HIDESUBMENU
},
156 {"screenshot" , ACTION_TAKE_SCREENSHOT
},
157 {"rename" , ACTION_RENAME_ITEM
},
158 {"togglewatched" , ACTION_TOGGLE_WATCHED
},
159 {"scanitem" , ACTION_SCAN_ITEM
},
160 {"reloadkeymaps" , ACTION_RELOAD_KEYMAPS
},
161 {"volumeup" , ACTION_VOLUME_UP
},
162 {"volumedown" , ACTION_VOLUME_DOWN
},
163 {"mute" , ACTION_MUTE
},
164 {"backspace" , ACTION_BACKSPACE
},
165 {"scrollup" , ACTION_SCROLL_UP
},
166 {"scrolldown" , ACTION_SCROLL_DOWN
},
167 {"analogfastforward" , ACTION_ANALOG_FORWARD
},
168 {"analogrewind" , ACTION_ANALOG_REWIND
},
169 {"moveitemup" , ACTION_MOVE_ITEM_UP
},
170 {"moveitemdown" , ACTION_MOVE_ITEM_DOWN
},
171 {"contextmenu" , ACTION_CONTEXT_MENU
},
172 {"shift" , ACTION_SHIFT
},
173 {"symbols" , ACTION_SYMBOLS
},
174 {"cursorleft" , ACTION_CURSOR_LEFT
},
175 {"cursorright" , ACTION_CURSOR_RIGHT
},
176 {"showtime" , ACTION_SHOW_OSD_TIME
},
177 {"analogseekforward" , ACTION_ANALOG_SEEK_FORWARD
},
178 {"analogseekback" , ACTION_ANALOG_SEEK_BACK
},
179 {"showpreset" , ACTION_VIS_PRESET_SHOW
},
180 {"presetlist" , ACTION_VIS_PRESET_LIST
},
181 {"nextpreset" , ACTION_VIS_PRESET_NEXT
},
182 {"previouspreset" , ACTION_VIS_PRESET_PREV
},
183 {"lockpreset" , ACTION_VIS_PRESET_LOCK
},
184 {"randompreset" , ACTION_VIS_PRESET_RANDOM
},
185 {"increasevisrating" , ACTION_VIS_RATE_PRESET_PLUS
},
186 {"decreasevisrating" , ACTION_VIS_RATE_PRESET_MINUS
},
187 {"showvideomenu" , ACTION_SHOW_VIDEOMENU
},
188 {"enter" , ACTION_ENTER
},
189 {"increaserating" , ACTION_INCREASE_RATING
},
190 {"decreaserating" , ACTION_DECREASE_RATING
},
191 {"togglefullscreen" , ACTION_TOGGLE_FULLSCREEN
},
192 {"nextscene" , ACTION_NEXT_SCENE
},
193 {"previousscene" , ACTION_PREV_SCENE
},
194 {"nextletter" , ACTION_NEXT_LETTER
},
195 {"prevletter" , ACTION_PREV_LETTER
},
196 {"jumpsms2" , ACTION_JUMP_SMS2
},
197 {"jumpsms3" , ACTION_JUMP_SMS3
},
198 {"jumpsms4" , ACTION_JUMP_SMS4
},
199 {"jumpsms5" , ACTION_JUMP_SMS5
},
200 {"jumpsms6" , ACTION_JUMP_SMS6
},
201 {"jumpsms7" , ACTION_JUMP_SMS7
},
202 {"jumpsms8" , ACTION_JUMP_SMS8
},
203 {"jumpsms9" , ACTION_JUMP_SMS9
},
204 {"filter" , ACTION_FILTER
},
205 {"filterclear" , ACTION_FILTER_CLEAR
},
206 {"filtersms2" , ACTION_FILTER_SMS2
},
207 {"filtersms3" , ACTION_FILTER_SMS3
},
208 {"filtersms4" , ACTION_FILTER_SMS4
},
209 {"filtersms5" , ACTION_FILTER_SMS5
},
210 {"filtersms6" , ACTION_FILTER_SMS6
},
211 {"filtersms7" , ACTION_FILTER_SMS7
},
212 {"filtersms8" , ACTION_FILTER_SMS8
},
213 {"filtersms9" , ACTION_FILTER_SMS9
},
214 {"firstpage" , ACTION_FIRST_PAGE
},
215 {"lastpage" , ACTION_LAST_PAGE
},
216 {"guiprofile" , ACTION_GUIPROFILE_BEGIN
},
217 {"red" , ACTION_TELETEXT_RED
},
218 {"green" , ACTION_TELETEXT_GREEN
},
219 {"yellow" , ACTION_TELETEXT_YELLOW
},
220 {"blue" , ACTION_TELETEXT_BLUE
},
221 {"increasepar" , ACTION_INCREASE_PAR
},
222 {"decreasepar" , ACTION_DECREASE_PAR
},
223 {"volampup" , ACTION_VOLAMP_UP
},
224 {"volampdown" , ACTION_VOLAMP_DOWN
},
225 {"createbookmark" , ACTION_CREATE_BOOKMARK
},
226 {"createepisodebookmark" , ACTION_CREATE_EPISODE_BOOKMARK
},
227 {"settingsreset" , ACTION_SETTINGS_RESET
},
228 {"settingslevelchange", ACTION_SETTINGS_LEVEL_CHANGE
},
230 // 3D movie playback/GUI
231 {"stereomode" , ACTION_STEREOMODE_SELECT
}, // cycle 3D modes, for now an alias for next
232 {"nextstereomode" , ACTION_STEREOMODE_NEXT
},
233 {"previousstereomode" , ACTION_STEREOMODE_PREVIOUS
},
234 {"togglestereomode" , ACTION_STEREOMODE_TOGGLE
},
235 {"stereomodetomono" , ACTION_STEREOMODE_TOMONO
},
238 {"channelup" , ACTION_CHANNEL_UP
},
239 {"channeldown" , ACTION_CHANNEL_DOWN
},
240 {"previouschannelgroup" , ACTION_PREVIOUS_CHANNELGROUP
},
241 {"nextchannelgroup" , ACTION_NEXT_CHANNELGROUP
},
242 {"playpvr" , ACTION_PVR_PLAY
},
243 {"playpvrtv" , ACTION_PVR_PLAY_TV
},
244 {"playpvrradio" , ACTION_PVR_PLAY_RADIO
},
245 {"record" , ACTION_RECORD
},
248 {"leftclick" , ACTION_MOUSE_LEFT_CLICK
},
249 {"rightclick" , ACTION_MOUSE_RIGHT_CLICK
},
250 {"middleclick" , ACTION_MOUSE_MIDDLE_CLICK
},
251 {"doubleclick" , ACTION_MOUSE_DOUBLE_CLICK
},
252 {"wheelup" , ACTION_MOUSE_WHEEL_UP
},
253 {"wheeldown" , ACTION_MOUSE_WHEEL_DOWN
},
254 {"mousedrag" , ACTION_MOUSE_DRAG
},
255 {"mousemove" , ACTION_MOUSE_MOVE
},
258 {"tap" , ACTION_TOUCH_TAP
},
259 {"longpress" , ACTION_TOUCH_LONGPRESS
},
260 {"pangesture" , ACTION_GESTURE_PAN
},
261 {"zoomgesture" , ACTION_GESTURE_ZOOM
},
262 {"rotategesture" , ACTION_GESTURE_ROTATE
},
263 {"swipeleft" , ACTION_GESTURE_SWIPE_LEFT
},
264 {"swiperight" , ACTION_GESTURE_SWIPE_RIGHT
},
265 {"swipeup" , ACTION_GESTURE_SWIPE_UP
},
266 {"swipedown" , ACTION_GESTURE_SWIPE_DOWN
},
269 { "noop" , ACTION_NOOP
}
272 static const ActionMapping windows
[] =
273 {{"home" , WINDOW_HOME
},
274 {"programs" , WINDOW_PROGRAMS
},
275 {"pictures" , WINDOW_PICTURES
},
276 {"filemanager" , WINDOW_FILES
},
277 {"files" , WINDOW_FILES
}, // backward compat
278 {"settings" , WINDOW_SETTINGS_MENU
},
279 {"music" , WINDOW_MUSIC
},
280 {"video" , WINDOW_VIDEOS
},
281 {"videos" , WINDOW_VIDEO_NAV
},
282 {"tv" , WINDOW_PVR
}, // backward compat
283 {"pvr" , WINDOW_PVR
},
284 {"pvrguideinfo" , WINDOW_DIALOG_PVR_GUIDE_INFO
},
285 {"pvrrecordinginfo" , WINDOW_DIALOG_PVR_RECORDING_INFO
},
286 {"pvrtimersetting" , WINDOW_DIALOG_PVR_TIMER_SETTING
},
287 {"pvrgroupmanager" , WINDOW_DIALOG_PVR_GROUP_MANAGER
},
288 {"pvrchannelmanager" , WINDOW_DIALOG_PVR_CHANNEL_MANAGER
},
289 {"pvrguidesearch" , WINDOW_DIALOG_PVR_GUIDE_SEARCH
},
290 {"pvrchannelscan" , WINDOW_DIALOG_PVR_CHANNEL_SCAN
},
291 {"pvrupdateprogress" , WINDOW_DIALOG_PVR_UPDATE_PROGRESS
},
292 {"pvrosdchannels" , WINDOW_DIALOG_PVR_OSD_CHANNELS
},
293 {"pvrosdguide" , WINDOW_DIALOG_PVR_OSD_GUIDE
},
294 {"pvrosddirector" , WINDOW_DIALOG_PVR_OSD_DIRECTOR
},
295 {"pvrosdcutter" , WINDOW_DIALOG_PVR_OSD_CUTTER
},
296 {"pvrosdteletext" , WINDOW_DIALOG_OSD_TELETEXT
},
297 {"systeminfo" , WINDOW_SYSTEM_INFORMATION
},
298 {"testpattern" , WINDOW_TEST_PATTERN
},
299 {"screencalibration" , WINDOW_SCREEN_CALIBRATION
},
300 {"guicalibration" , WINDOW_SCREEN_CALIBRATION
}, // backward compat
301 {"picturessettings" , WINDOW_SETTINGS_MYPICTURES
},
302 {"programssettings" , WINDOW_SETTINGS_MYPROGRAMS
},
303 {"weathersettings" , WINDOW_SETTINGS_MYWEATHER
},
304 {"musicsettings" , WINDOW_SETTINGS_MYMUSIC
},
305 {"systemsettings" , WINDOW_SETTINGS_SYSTEM
},
306 {"videossettings" , WINDOW_SETTINGS_MYVIDEOS
},
307 {"networksettings" , WINDOW_SETTINGS_SERVICE
}, // backward compat
308 {"servicesettings" , WINDOW_SETTINGS_SERVICE
},
309 {"appearancesettings" , WINDOW_SETTINGS_APPEARANCE
},
310 {"pvrsettings" , WINDOW_SETTINGS_MYPVR
},
311 {"tvsettings" , WINDOW_SETTINGS_MYPVR
}, // backward compat
312 {"scripts" , WINDOW_PROGRAMS
}, // backward compat
313 {"videofiles" , WINDOW_VIDEO_FILES
},
314 {"videolibrary" , WINDOW_VIDEO_NAV
},
315 {"videoplaylist" , WINDOW_VIDEO_PLAYLIST
},
316 {"loginscreen" , WINDOW_LOGIN_SCREEN
},
317 {"profiles" , WINDOW_SETTINGS_PROFILES
},
318 {"skinsettings" , WINDOW_SKIN_SETTINGS
},
319 {"addonbrowser" , WINDOW_ADDON_BROWSER
},
320 {"yesnodialog" , WINDOW_DIALOG_YES_NO
},
321 {"progressdialog" , WINDOW_DIALOG_PROGRESS
},
322 {"virtualkeyboard" , WINDOW_DIALOG_KEYBOARD
},
323 {"volumebar" , WINDOW_DIALOG_VOLUME_BAR
},
324 {"submenu" , WINDOW_DIALOG_SUB_MENU
},
325 {"favourites" , WINDOW_DIALOG_FAVOURITES
},
326 {"contextmenu" , WINDOW_DIALOG_CONTEXT_MENU
},
327 {"infodialog" , WINDOW_DIALOG_KAI_TOAST
},
328 {"numericinput" , WINDOW_DIALOG_NUMERIC
},
329 {"gamepadinput" , WINDOW_DIALOG_GAMEPAD
},
330 {"shutdownmenu" , WINDOW_DIALOG_BUTTON_MENU
},
331 {"mutebug" , WINDOW_DIALOG_MUTE_BUG
},
332 {"playercontrols" , WINDOW_DIALOG_PLAYER_CONTROLS
},
333 {"seekbar" , WINDOW_DIALOG_SEEK_BAR
},
334 {"musicosd" , WINDOW_DIALOG_MUSIC_OSD
},
335 {"addonsettings" , WINDOW_DIALOG_ADDON_SETTINGS
},
336 {"visualisationsettings" , WINDOW_DIALOG_ADDON_SETTINGS
}, // backward compat
337 {"visualisationpresetlist" , WINDOW_DIALOG_VIS_PRESET_LIST
},
338 {"osdvideosettings" , WINDOW_DIALOG_VIDEO_OSD_SETTINGS
},
339 {"osdaudiosettings" , WINDOW_DIALOG_AUDIO_OSD_SETTINGS
},
340 {"videobookmarks" , WINDOW_DIALOG_VIDEO_BOOKMARKS
},
341 {"filebrowser" , WINDOW_DIALOG_FILE_BROWSER
},
342 {"networksetup" , WINDOW_DIALOG_NETWORK_SETUP
},
343 {"mediasource" , WINDOW_DIALOG_MEDIA_SOURCE
},
344 {"profilesettings" , WINDOW_DIALOG_PROFILE_SETTINGS
},
345 {"locksettings" , WINDOW_DIALOG_LOCK_SETTINGS
},
346 {"contentsettings" , WINDOW_DIALOG_CONTENT_SETTINGS
},
347 {"songinformation" , WINDOW_DIALOG_SONG_INFO
},
348 {"smartplaylisteditor" , WINDOW_DIALOG_SMART_PLAYLIST_EDITOR
},
349 {"smartplaylistrule" , WINDOW_DIALOG_SMART_PLAYLIST_RULE
},
350 {"busydialog" , WINDOW_DIALOG_BUSY
},
351 {"pictureinfo" , WINDOW_DIALOG_PICTURE_INFO
},
352 {"accesspoints" , WINDOW_DIALOG_ACCESS_POINTS
},
353 {"fullscreeninfo" , WINDOW_DIALOG_FULLSCREEN_INFO
},
354 {"karaokeselector" , WINDOW_DIALOG_KARAOKE_SONGSELECT
},
355 {"karaokelargeselector" , WINDOW_DIALOG_KARAOKE_SELECTOR
},
356 {"sliderdialog" , WINDOW_DIALOG_SLIDER
},
357 {"addoninformation" , WINDOW_DIALOG_ADDON_INFO
},
358 {"subtitlesearch" , WINDOW_DIALOG_SUBTITLES
},
359 {"musicplaylist" , WINDOW_MUSIC_PLAYLIST
},
360 {"musicfiles" , WINDOW_MUSIC_FILES
},
361 {"musiclibrary" , WINDOW_MUSIC_NAV
},
362 {"musicplaylisteditor" , WINDOW_MUSIC_PLAYLIST_EDITOR
},
363 {"teletext" , WINDOW_DIALOG_OSD_TELETEXT
},
364 {"selectdialog" , WINDOW_DIALOG_SELECT
},
365 {"musicinformation" , WINDOW_DIALOG_MUSIC_INFO
},
366 {"okdialog" , WINDOW_DIALOG_OK
},
367 {"movieinformation" , WINDOW_DIALOG_VIDEO_INFO
},
368 {"textviewer" , WINDOW_DIALOG_TEXT_VIEWER
},
369 {"fullscreenvideo" , WINDOW_FULLSCREEN_VIDEO
},
370 {"fullscreenlivetv" , WINDOW_FULLSCREEN_LIVETV
}, // virtual window/keymap section for PVR specific bindings in fullscreen playback (which internally uses WINDOW_FULLSCREEN_VIDEO)
371 {"visualisation" , WINDOW_VISUALISATION
},
372 {"slideshow" , WINDOW_SLIDESHOW
},
373 {"filestackingdialog" , WINDOW_DIALOG_FILESTACKING
},
374 {"karaoke" , WINDOW_KARAOKELYRICS
},
375 {"weather" , WINDOW_WEATHER
},
376 {"screensaver" , WINDOW_SCREENSAVER
},
377 {"videoosd" , WINDOW_DIALOG_VIDEO_OSD
},
378 {"videomenu" , WINDOW_VIDEO_MENU
},
379 {"videotimeseek" , WINDOW_VIDEO_TIME_SEEK
},
380 {"musicoverlay" , WINDOW_DIALOG_MUSIC_OVERLAY
},
381 {"videooverlay" , WINDOW_DIALOG_VIDEO_OVERLAY
},
382 {"startwindow" , WINDOW_START
},
383 {"startup" , WINDOW_STARTUP_ANIM
},
384 {"peripherals" , WINDOW_DIALOG_PERIPHERAL_MANAGER
},
385 {"peripheralsettings" , WINDOW_DIALOG_PERIPHERAL_SETTINGS
},
386 {"extendedprogressdialog" , WINDOW_DIALOG_EXT_PROGRESS
},
387 {"mediafilter" , WINDOW_DIALOG_MEDIA_FILTER
},
388 {"addon" , WINDOW_ADDON_START
}};
390 static const ActionMapping mousecommands
[] =
392 { "leftclick", ACTION_MOUSE_LEFT_CLICK
},
393 { "rightclick", ACTION_MOUSE_RIGHT_CLICK
},
394 { "middleclick", ACTION_MOUSE_MIDDLE_CLICK
},
395 { "doubleclick", ACTION_MOUSE_DOUBLE_CLICK
},
396 { "wheelup", ACTION_MOUSE_WHEEL_UP
},
397 { "wheeldown", ACTION_MOUSE_WHEEL_DOWN
},
398 { "mousedrag", ACTION_MOUSE_DRAG
},
399 { "mousemove", ACTION_MOUSE_MOVE
}
402 static const ActionMapping touchcommands
[] =
404 { "tap", ACTION_TOUCH_TAP
},
405 { "longpress", ACTION_TOUCH_LONGPRESS
},
406 { "pan", ACTION_GESTURE_PAN
},
407 { "zoom", ACTION_GESTURE_ZOOM
},
408 { "rotate", ACTION_GESTURE_ROTATE
},
409 { "swipeleft", ACTION_GESTURE_SWIPE_LEFT
},
410 { "swiperight", ACTION_GESTURE_SWIPE_RIGHT
},
411 { "swipeup", ACTION_GESTURE_SWIPE_UP
},
412 { "swipedown", ACTION_GESTURE_SWIPE_DOWN
}
415 static const WindowMapping fallbackWindows
[] =
417 { WINDOW_FULLSCREEN_LIVETV
, WINDOW_FULLSCREEN_VIDEO
},
418 { WINDOW_DIALOG_FULLSCREEN_INFO
, WINDOW_FULLSCREEN_VIDEO
}
421 #ifdef TARGET_WINDOWS
422 static const ActionMapping appcommands
[] =
424 { "browser_back", APPCOMMAND_BROWSER_BACKWARD
},
425 { "browser_forward", APPCOMMAND_BROWSER_FORWARD
},
426 { "browser_refresh", APPCOMMAND_BROWSER_REFRESH
},
427 { "browser_stop", APPCOMMAND_BROWSER_STOP
},
428 { "browser_search", APPCOMMAND_BROWSER_SEARCH
},
429 { "browser_favorites", APPCOMMAND_BROWSER_FAVORITES
},
430 { "browser_home", APPCOMMAND_BROWSER_HOME
},
431 { "volume_mute", APPCOMMAND_VOLUME_MUTE
},
432 { "volume_down", APPCOMMAND_VOLUME_DOWN
},
433 { "volume_up", APPCOMMAND_VOLUME_UP
},
434 { "next_track", APPCOMMAND_MEDIA_NEXTTRACK
},
435 { "prev_track", APPCOMMAND_MEDIA_PREVIOUSTRACK
},
436 { "stop", APPCOMMAND_MEDIA_STOP
},
437 { "play_pause", APPCOMMAND_MEDIA_PLAY_PAUSE
},
438 { "launch_mail", APPCOMMAND_LAUNCH_MAIL
},
439 { "launch_media_select", APPCOMMAND_LAUNCH_MEDIA_SELECT
},
440 { "launch_app1", APPCOMMAND_LAUNCH_APP1
},
441 { "launch_app2", APPCOMMAND_LAUNCH_APP2
},
442 { "play", APPCOMMAND_MEDIA_PLAY
},
443 { "pause", APPCOMMAND_MEDIA_PAUSE
},
444 { "fastforward", APPCOMMAND_MEDIA_FAST_FORWARD
},
445 { "rewind", APPCOMMAND_MEDIA_REWIND
},
446 { "channelup", APPCOMMAND_MEDIA_CHANNEL_UP
},
447 { "channeldown", APPCOMMAND_MEDIA_CHANNEL_DOWN
}
451 CButtonTranslator
& CButtonTranslator::GetInstance()
453 static CButtonTranslator sl_instance
;
457 CButtonTranslator::CButtonTranslator()
459 m_deviceList
.clear();
463 #if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
464 void CButtonTranslator::ClearLircButtonMapEntries()
466 vector
<lircButtonMap
*> maps
;
467 for (map
<CStdString
,lircButtonMap
*>::iterator it
= lircRemotesMap
.begin();
468 it
!= lircRemotesMap
.end();++it
)
469 maps
.push_back(it
->second
);
470 sort(maps
.begin(),maps
.end());
471 vector
<lircButtonMap
*>::iterator itend
= unique(maps
.begin(),maps
.end());
472 for (vector
<lircButtonMap
*>::iterator it
= maps
.begin(); it
!= itend
;++it
)
477 CButtonTranslator::~CButtonTranslator()
479 #if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
480 ClearLircButtonMapEntries();
484 // Add the supplied device name to the list of connected devices
485 void CButtonTranslator::AddDevice(CStdString
& strDevice
)
487 // Only add the device if it isn't already in the list
488 std::list
<CStdString
>::iterator it
;
489 for (it
= m_deviceList
.begin(); it
!= m_deviceList
.end(); it
++)
490 if (*it
== strDevice
)
494 m_deviceList
.push_back(strDevice
);
497 // New device added so reload the key mappings
501 void CButtonTranslator::RemoveDevice(CStdString
& strDevice
)
504 std::list
<CStdString
>::iterator it
;
505 for (it
= m_deviceList
.begin(); it
!= m_deviceList
.end(); it
++)
506 if (*it
== strDevice
)
508 if (it
== m_deviceList
.end())
512 m_deviceList
.remove(strDevice
);
514 // Device removed so reload the key mappings
518 bool CButtonTranslator::Load(bool AlwaysLoad
)
520 m_translatorMap
.clear();
522 // Directories to search for keymaps. They're applied in this order,
523 // so keymaps in profile/keymaps/ override e.g. system/keymaps
524 static const char* DIRS_TO_CHECK
[] = {
525 "special://xbmc/system/keymaps/",
526 "special://masterprofile/keymaps/",
527 "special://profile/keymaps/"
529 bool success
= false;
531 for (unsigned int dirIndex
= 0; dirIndex
< sizeof(DIRS_TO_CHECK
)/sizeof(DIRS_TO_CHECK
[0]); ++dirIndex
)
533 if (XFILE::CDirectory::Exists(DIRS_TO_CHECK
[dirIndex
]))
536 XFILE::CDirectory::GetDirectory(DIRS_TO_CHECK
[dirIndex
], files
, ".xml");
537 // Sort the list for filesystem based priorities, e.g. 01-keymap.xml, 02-keymap-overrides.xml
538 files
.Sort(SortByFile
, SortOrderAscending
);
539 for(int fileIndex
= 0; fileIndex
<files
.Size(); ++fileIndex
)
541 if (!files
[fileIndex
]->m_bIsFolder
)
542 success
|= LoadKeymap(files
[fileIndex
]->GetPath());
545 // Load mappings for any HID devices we have connected
546 std::list
<CStdString
>::iterator it
;
547 for (it
= m_deviceList
.begin(); it
!= m_deviceList
.end(); it
++)
549 CStdString devicedir
= DIRS_TO_CHECK
[dirIndex
];
550 devicedir
.append(*it
);
551 devicedir
.append("/");
552 if( XFILE::CDirectory::Exists(devicedir
) )
555 XFILE::CDirectory::GetDirectory(devicedir
, files
, ".xml");
556 // Sort the list for filesystem based priorities, e.g. 01-keymap.xml, 02-keymap-overrides.xml
557 files
.Sort(SortByFile
, SortOrderAscending
);
558 for(int fileIndex
= 0; fileIndex
<files
.Size(); ++fileIndex
)
560 if (!files
[fileIndex
]->m_bIsFolder
)
561 success
|= LoadKeymap(files
[fileIndex
]->GetPath());
570 CLog::Log(LOGERROR
, "Error loading keymaps from: %s or %s or %s", DIRS_TO_CHECK
[0], DIRS_TO_CHECK
[1], DIRS_TO_CHECK
[2]);
574 #if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
576 #define REMOTEMAP "Lircmap.xml"
578 #define REMOTEMAP "IRSSmap.xml"
580 CStdString lircmapPath
= URIUtils::AddFileToFolder("special://xbmc/system/", REMOTEMAP
);
581 lircRemotesMap
.clear();
582 if(CFile::Exists(lircmapPath
))
583 success
|= LoadLircMap(lircmapPath
);
585 CLog::Log(LOGDEBUG
, "CButtonTranslator::Load - no system %s found, skipping", REMOTEMAP
);
587 lircmapPath
= CProfilesManager::Get().GetUserDataItem(REMOTEMAP
);
588 if(CFile::Exists(lircmapPath
))
589 success
|= LoadLircMap(lircmapPath
);
591 CLog::Log(LOGDEBUG
, "CButtonTranslator::Load - no userdata %s found, skipping", REMOTEMAP
);
594 CLog::Log(LOGERROR
, "CButtonTranslator::Load - unable to load remote map %s", REMOTEMAP
);
595 // don't return false - it is to only indicate a fatal error (which this is not)
603 bool CButtonTranslator::LoadKeymap(const CStdString
&keymapPath
)
607 CLog::Log(LOGINFO
, "Loading %s", keymapPath
.c_str());
608 if (!xmlDoc
.LoadFile(keymapPath
))
610 CLog::Log(LOGERROR
, "Error loading keymap: %s, Line %d\n%s", keymapPath
.c_str(), xmlDoc
.ErrorRow(), xmlDoc
.ErrorDesc());
613 TiXmlElement
* pRoot
= xmlDoc
.RootElement();
616 CLog::Log(LOGERROR
, "Error getting keymap root: %s", keymapPath
.c_str());
619 CStdString strValue
= pRoot
->Value();
620 if ( strValue
!= "keymap")
622 CLog::Log(LOGERROR
, "%s Doesn't contain <keymap>", keymapPath
.c_str());
625 // run through our window groups
626 TiXmlNode
* pWindow
= pRoot
->FirstChild();
629 if (pWindow
->Type() == TiXmlNode::TINYXML_ELEMENT
)
631 int windowID
= WINDOW_INVALID
;
632 const char *szWindow
= pWindow
->Value();
635 if (strcmpi(szWindow
, "global") == 0)
638 windowID
= TranslateWindow(szWindow
);
640 MapWindowActions(pWindow
, windowID
);
642 pWindow
= pWindow
->NextSibling();
648 #if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
649 bool CButtonTranslator::LoadLircMap(const CStdString
&lircmapPath
)
652 #define REMOTEMAPTAG "lircmap"
654 #define REMOTEMAPTAG "irssmap"
656 // load our xml file, and fill up our mapping tables
659 // Load the config file
660 CLog::Log(LOGINFO
, "Loading %s", lircmapPath
.c_str());
661 if (!xmlDoc
.LoadFile(lircmapPath
))
663 CLog::Log(LOGERROR
, "%s, Line %d\n%s", lircmapPath
.c_str(), xmlDoc
.ErrorRow(), xmlDoc
.ErrorDesc());
664 return false; // This is so people who don't have the file won't fail, just warn
667 TiXmlElement
* pRoot
= xmlDoc
.RootElement();
668 CStdString strValue
= pRoot
->Value();
669 if (strValue
!= REMOTEMAPTAG
)
671 CLog::Log(LOGERROR
, "%sl Doesn't contain <%s>", lircmapPath
.c_str(), REMOTEMAPTAG
);
675 // run through our window groups
676 TiXmlNode
* pRemote
= pRoot
->FirstChild();
679 if (pRemote
->Type() == TiXmlNode::TINYXML_ELEMENT
)
681 const char *szRemote
= pRemote
->Value();
684 TiXmlAttribute
* pAttr
= pRemote
->ToElement()->FirstAttribute();
685 const char* szDeviceName
= pAttr
->Value();
686 MapRemote(pRemote
, szDeviceName
);
689 pRemote
= pRemote
->NextSibling();
695 void CButtonTranslator::MapRemote(TiXmlNode
*pRemote
, const char* szDevice
)
697 CLog::Log(LOGINFO
, "* Adding remote mapping for device '%s'", szDevice
);
698 vector
<string
> RemoteNames
;
699 map
<CStdString
, lircButtonMap
*>::iterator it
= lircRemotesMap
.find(szDevice
);
700 if (it
== lircRemotesMap
.end())
701 lircRemotesMap
[szDevice
] = new lircButtonMap
;
702 lircButtonMap
& buttons
= *lircRemotesMap
[szDevice
];
704 TiXmlElement
*pButton
= pRemote
->FirstChildElement();
707 if (strcmpi(pButton
->Value(), "altname")==0)
708 RemoteNames
.push_back(string(pButton
->GetText()));
711 if (pButton
->FirstChild() && pButton
->FirstChild()->Value())
712 buttons
[pButton
->FirstChild()->Value()] = pButton
->Value();
715 pButton
= pButton
->NextSiblingElement();
717 for (vector
<string
>::iterator it
= RemoteNames
.begin();
718 it
!= RemoteNames
.end();++it
)
720 CLog::Log(LOGINFO
, "* Linking remote mapping for '%s' to '%s'", szDevice
, it
->c_str());
721 lircRemotesMap
[*it
] = &buttons
;
725 int CButtonTranslator::TranslateLircRemoteString(const char* szDevice
, const char *szButton
)
728 map
<CStdString
, lircButtonMap
*>::iterator it
= lircRemotesMap
.find(szDevice
);
729 if (it
== lircRemotesMap
.end())
733 lircButtonMap::iterator it2
= (*it
).second
->find(szButton
);
734 if (it2
== (*it
).second
->end())
737 // Convert the button to code
738 if (strnicmp((*it2
).second
.c_str(), "obc", 3) == 0)
739 return TranslateUniversalRemoteString((*it2
).second
.c_str());
741 return TranslateRemoteString((*it2
).second
.c_str());
745 #if defined(HAS_SDL_JOYSTICK) || defined(HAS_EVENT_SERVER)
746 void CButtonTranslator::MapJoystickActions(int windowID
, TiXmlNode
*pJoystick
)
748 string joyname
= JOYSTICK_DEFAULT_MAP
; // default global map name
749 vector
<string
> joynames
;
750 map
<int, string
> buttonMap
;
751 map
<int, string
> axisMap
;
752 map
<int, string
> hatMap
;
754 TiXmlElement
*pJoy
= pJoystick
->ToElement();
755 if (pJoy
&& pJoy
->Attribute("name"))
756 joyname
= pJoy
->Attribute("name");
758 CLog::Log(LOGNOTICE
, "No Joystick name specified, loading default map");
760 joynames
.push_back(joyname
);
763 TiXmlElement
*pButton
= pJoystick
->FirstChildElement();
767 const char *szAction
;
770 szType
= pButton
->Value();
771 szAction
= pButton
->GetText();
772 if (szAction
== NULL
)
776 if ((pButton
->QueryIntAttribute("id", &id
) == TIXML_SUCCESS
) && id
>=0 && id
<=256)
778 if (strcmpi(szType
, "button")==0)
780 buttonMap
[id
] = string(szAction
);
782 else if (strcmpi(szType
, "axis")==0)
785 if (pButton
->QueryIntAttribute("limit", &limit
) == TIXML_SUCCESS
)
788 axisMap
[-id
] = string(szAction
);
790 axisMap
[id
] = string(szAction
);
792 axisMap
[id
|0xFFFF0000] = string(szAction
);
795 axisMap
[id
] = string(szAction
);
796 axisMap
[-id
] = string(szAction
);
797 CLog::Log(LOGERROR
, "Error in joystick map, invalid limit specified %d for axis %d", limit
, id
);
802 axisMap
[id
] = string(szAction
);
803 axisMap
[-id
] = string(szAction
);
806 else if (strcmpi(szType
, "hat")==0)
809 if (pButton
->QueryValueAttribute("position", &position
) == TIXML_SUCCESS
)
811 uint32_t hatID
= id
|0xFFF00000;
812 if (position
.compare("up") == 0)
813 hatMap
[(JACTIVE_HAT_UP
<<16)|hatID
] = string(szAction
);
814 else if (position
.compare("down") == 0)
815 hatMap
[(JACTIVE_HAT_DOWN
<<16)|hatID
] = string(szAction
);
816 else if (position
.compare("right") == 0)
817 hatMap
[(JACTIVE_HAT_RIGHT
<<16)|hatID
] = string(szAction
);
818 else if (position
.compare("left") == 0)
819 hatMap
[(JACTIVE_HAT_LEFT
<<16)|hatID
] = string(szAction
);
821 CLog::Log(LOGERROR
, "Error in joystick map, invalid position specified %s for axis %d", position
.c_str(), id
);
825 CLog::Log(LOGERROR
, "Error reading joystick map element, unknown button type: %s", szType
);
827 else if (strcmpi(szType
, "altname")==0)
828 joynames
.push_back(string(szAction
));
830 CLog::Log(LOGERROR
, "Error reading joystick map element, Invalid id: %d", id
);
833 CLog::Log(LOGERROR
, "Error reading joystick map element, skipping");
835 pButton
= pButton
->NextSiblingElement();
837 vector
<string
>::iterator it
= joynames
.begin();
838 while (it
!=joynames
.end())
840 m_joystickButtonMap
[*it
][windowID
] = buttonMap
;
841 m_joystickAxisMap
[*it
][windowID
] = axisMap
;
842 m_joystickHatMap
[*it
][windowID
] = hatMap
;
843 // CLog::Log(LOGDEBUG, "Found Joystick map for window %d using %s", windowID, it->c_str());
848 bool CButtonTranslator::TranslateJoystickString(int window
, const char* szDevice
, int id
, short inputType
, int& action
, CStdString
& strAction
, bool &fullrange
)
852 // resolve the correct JoystickMap
853 map
<string
, JoystickMap
> *jmap
;
854 if (inputType
== JACTIVE_AXIS
)
855 jmap
= &m_joystickAxisMap
;
856 else if (inputType
== JACTIVE_BUTTON
)
857 jmap
= &m_joystickButtonMap
;
858 else if (inputType
== JACTIVE_HAT
)
859 jmap
= &m_joystickHatMap
;
862 CLog::Log(LOGERROR
, "Error reading joystick input type '%i'", (int) inputType
);
866 map
<string
, JoystickMap
>::iterator it
= jmap
->find(szDevice
);
869 it
= jmap
->find(JOYSTICK_DEFAULT_MAP
); // default global map name
874 JoystickMap wmap
= it
->second
;
876 // try to get the action from the current window
877 action
= GetActionCode(window
, id
, wmap
, strAction
, fullrange
);
879 // if it's invalid, try to get it from a fallback window or the global map
882 int fallbackWindow
= GetFallbackWindow(window
);
883 if (fallbackWindow
> -1)
884 action
= GetActionCode(fallbackWindow
, id
, wmap
, strAction
, fullrange
);
885 // still no valid action? use global map
887 action
= GetActionCode(-1, id
, wmap
, strAction
, fullrange
);
893 bool CButtonTranslator::TranslateTouchAction(int window
, int touchAction
, int touchPointers
, int &action
)
896 if (touchPointers
<= 0)
899 touchAction
+= touchPointers
- 1;
900 touchAction
|= KEY_TOUCH
;
902 action
= GetTouchActionCode(window
, touchAction
);
904 action
= GetTouchActionCode(-1, touchAction
);
909 int CButtonTranslator::GetActionCode(int window
, int action
)
911 map
<int, buttonMap
>::const_iterator it
= m_translatorMap
.find(window
);
912 if (it
== m_translatorMap
.end())
915 buttonMap::const_iterator it2
= it
->second
.find(action
);
916 if (it2
== it
->second
.end())
919 return it2
->second
.id
;
923 * Translates a joystick input to an action code
925 int CButtonTranslator::GetActionCode(int window
, int id
, const JoystickMap
&wmap
, CStdString
&strAction
, bool &fullrange
) const
930 JoystickMap::const_iterator it
= wmap
.find(window
);
931 if (it
!= wmap
.end())
933 const map
<int, string
> &windowbmap
= it
->second
;
934 map
<int, string
>::const_iterator it2
= windowbmap
.find(id
);
935 if (it2
!= windowbmap
.end())
937 strAction
= (it2
->second
).c_str();
941 it2
= windowbmap
.find(abs(id
)|0xFFFF0000);
942 if (it2
!= windowbmap
.end())
944 strAction
= (it2
->second
).c_str();
950 it2
= windowbmap
.find(id
|0xFFF00000);
951 if (it2
!= windowbmap
.end())
953 strAction
= (it2
->second
).c_str();
959 TranslateActionString(strAction
.c_str(), action
);
964 void CButtonTranslator::GetActions(std::vector
<std::string
> &actionList
)
966 unsigned int size
= sizeof(actions
) / sizeof(ActionMapping
);
968 actionList
.reserve(size
);
969 for (unsigned int index
= 0; index
< size
; index
++)
970 actionList
.push_back(actions
[index
].name
);
973 void CButtonTranslator::GetWindows(std::vector
<std::string
> &windowList
)
975 unsigned int size
= sizeof(windows
) / sizeof(ActionMapping
);
977 windowList
.reserve(size
);
978 for (unsigned int index
= 0; index
< size
; index
++)
979 windowList
.push_back(windows
[index
].name
);
982 int CButtonTranslator::GetFallbackWindow(int windowID
)
984 for (unsigned int index
= 0; index
< sizeof(fallbackWindows
) / sizeof(fallbackWindows
[0]); ++index
)
986 if (fallbackWindows
[index
].origin
== windowID
)
987 return fallbackWindows
[index
].target
;
989 // for addon windows use WINDOW_ADDON_START
990 // because id is dynamic
991 if (windowID
>= WINDOW_ADDON_START
&& windowID
<= WINDOW_ADDON_END
)
992 return WINDOW_ADDON_START
;
997 CAction
CButtonTranslator::GetAction(int window
, const CKey
&key
, bool fallback
)
999 CStdString strAction
;
1000 // try to get the action from the current window
1001 int actionID
= GetActionCode(window
, key
, strAction
);
1002 // if it's invalid, try to get it from the global map
1003 if (actionID
== 0 && fallback
)
1005 int fallbackWindow
= GetFallbackWindow(window
);
1006 if (fallbackWindow
> -1)
1007 actionID
= GetActionCode(fallbackWindow
, key
, strAction
);
1008 // still no valid action? use global map
1010 actionID
= GetActionCode( -1, key
, strAction
);
1012 // Now fill our action structure
1013 CAction
action(actionID
, strAction
, key
);
1017 int CButtonTranslator::GetActionCode(int window
, const CKey
&key
, CStdString
&strAction
) const
1019 uint32_t code
= key
.GetButtonCode();
1021 map
<int, buttonMap
>::const_iterator it
= m_translatorMap
.find(window
);
1022 if (it
== m_translatorMap
.end())
1024 buttonMap::const_iterator it2
= (*it
).second
.find(code
);
1026 while (it2
!= (*it
).second
.end())
1028 action
= (*it2
).second
.id
;
1029 strAction
= (*it2
).second
.strID
;
1030 it2
= (*it
).second
.end();
1033 // Some buttoncodes changed in Hardy
1034 if (action
== 0 && (code
& KEY_VKEY
) == KEY_VKEY
&& (code
& 0x0F00))
1036 CLog::Log(LOGDEBUG
, "%s: Trying Hardy keycode for %#04x", __FUNCTION__
, code
);
1038 buttonMap::const_iterator it2
= (*it
).second
.find(code
);
1039 while (it2
!= (*it
).second
.end())
1041 action
= (*it2
).second
.id
;
1042 strAction
= (*it2
).second
.strID
;
1043 it2
= (*it
).second
.end();
1050 void CButtonTranslator::MapAction(uint32_t buttonCode
, const char *szAction
, buttonMap
&map
)
1052 int action
= ACTION_NONE
;
1053 if (!TranslateActionString(szAction
, action
) || !buttonCode
)
1054 return; // no valid action, or an invalid buttoncode
1056 // have a valid action, and a valid button - map it.
1057 // check to see if we've already got this (button,action) pair defined
1058 buttonMap::iterator it
= map
.find(buttonCode
);
1059 if (it
== map
.end() || (*it
).second
.id
!= action
|| (*it
).second
.strID
!= szAction
)
1061 // NOTE: This multimap is only being used as a normal map at this point (no support
1062 // for multiple actions per key)
1063 if (it
!= map
.end())
1065 CButtonAction button
;
1067 button
.strID
= szAction
;
1068 map
.insert(pair
<uint32_t, CButtonAction
>(buttonCode
, button
));
1072 bool CButtonTranslator::HasDeviceType(TiXmlNode
*pWindow
, CStdString type
)
1074 return pWindow
->FirstChild(type
) != NULL
;
1077 void CButtonTranslator::MapWindowActions(TiXmlNode
*pWindow
, int windowID
)
1079 if (!pWindow
|| windowID
== WINDOW_INVALID
)
1084 const char* types
[] = {"gamepad", "remote", "universalremote", "keyboard", "mouse", "appcommand", NULL
};
1085 for (int i
= 0; types
[i
]; ++i
)
1087 CStdString
type(types
[i
]);
1088 if (HasDeviceType(pWindow
, type
))
1091 std::map
<int, buttonMap
>::iterator it
= m_translatorMap
.find(windowID
);
1092 if (it
!= m_translatorMap
.end())
1095 m_translatorMap
.erase(it
);
1098 pDevice
= pWindow
->FirstChild(type
);
1100 TiXmlElement
*pButton
= pDevice
->FirstChildElement();
1104 uint32_t buttonCode
=0;
1105 if (type
== "gamepad")
1106 buttonCode
= TranslateGamepadString(pButton
->Value());
1107 else if (type
== "remote")
1108 buttonCode
= TranslateRemoteString(pButton
->Value());
1109 else if (type
== "universalremote")
1110 buttonCode
= TranslateUniversalRemoteString(pButton
->Value());
1111 else if (type
== "keyboard")
1112 buttonCode
= TranslateKeyboardButton(pButton
);
1113 else if (type
== "mouse")
1114 buttonCode
= TranslateMouseCommand(pButton
->Value());
1115 else if (type
== "appcommand")
1116 buttonCode
= TranslateAppCommand(pButton
->Value());
1118 if (buttonCode
&& pButton
->FirstChild())
1119 MapAction(buttonCode
, pButton
->FirstChild()->Value(), map
);
1120 pButton
= pButton
->NextSiblingElement();
1123 // add our map to our table
1125 m_translatorMap
.insert(pair
<int, buttonMap
>( windowID
, map
));
1129 #if defined(HAS_SDL_JOYSTICK) || defined(HAS_EVENT_SERVER)
1130 if ((pDevice
= pWindow
->FirstChild("joystick")) != NULL
)
1132 // map joystick actions
1135 MapJoystickActions(windowID
, pDevice
);
1136 pDevice
= pDevice
->NextSibling("joystick");
1141 if ((pDevice
= pWindow
->FirstChild("touch")) != NULL
)
1143 // map touch actions
1146 MapTouchActions(windowID
, pDevice
);
1147 pDevice
= pDevice
->NextSibling("touch");
1152 bool CButtonTranslator::TranslateActionString(const char *szAction
, int &action
)
1154 action
= ACTION_NONE
;
1155 CStdString strAction
= szAction
;
1156 StringUtils::ToLower(strAction
);
1157 if (CBuiltins::HasCommand(strAction
))
1158 action
= ACTION_BUILT_IN_FUNCTION
;
1160 for (unsigned int index
=0;index
< sizeof(actions
)/sizeof(actions
[0]);++index
)
1162 if (strAction
.Equals(actions
[index
].name
))
1164 action
= actions
[index
].action
;
1169 if (action
== ACTION_NONE
)
1171 CLog::Log(LOGERROR
, "Keymapping error: no such action '%s' defined", strAction
.c_str());
1178 CStdString
CButtonTranslator::TranslateWindow(int windowID
)
1180 for (unsigned int index
= 0; index
< sizeof(windows
) / sizeof(windows
[0]); ++index
)
1182 if (windows
[index
].action
== windowID
)
1183 return windows
[index
].name
;
1188 int CButtonTranslator::TranslateWindow(const CStdString
&window
)
1190 CStdString
strWindow(window
);
1191 if (strWindow
.empty())
1192 return WINDOW_INVALID
;
1193 StringUtils::ToLower(strWindow
);
1195 if (StringUtils::EndsWith(strWindow
, ".xml"))
1196 strWindow
= strWindow
.substr(0, strWindow
.size() - 4);
1198 // window12345, for custom window to be keymapped
1199 if (strWindow
.length() > 6 && StringUtils::StartsWithNoCase(strWindow
, "window"))
1200 strWindow
= strWindow
.substr(6);
1201 if (StringUtils::StartsWithNoCase(strWindow
, "my")) // drop "my" prefix
1202 strWindow
= strWindow
.substr(2);
1203 if (StringUtils::IsNaturalNumber(strWindow
))
1205 // allow a full window id or a delta id
1206 int iWindow
= atoi(strWindow
.c_str());
1207 if (iWindow
> WINDOW_INVALID
)
1209 return WINDOW_HOME
+ iWindow
;
1212 // run through the window structure
1213 for (unsigned int index
= 0; index
< sizeof(windows
) / sizeof(windows
[0]); ++index
)
1215 if (strWindow
.Equals(windows
[index
].name
))
1216 return windows
[index
].action
;
1219 CLog::Log(LOGERROR
, "Window Translator: Can't find window %s", strWindow
.c_str());
1220 return WINDOW_INVALID
;
1223 uint32_t CButtonTranslator::TranslateGamepadString(const char *szButton
)
1227 uint32_t buttonCode
= 0;
1228 CStdString strButton
= szButton
;
1229 StringUtils::ToLower(strButton
);
1230 if (strButton
.Equals("a")) buttonCode
= KEY_BUTTON_A
;
1231 else if (strButton
.Equals("b")) buttonCode
= KEY_BUTTON_B
;
1232 else if (strButton
.Equals("x")) buttonCode
= KEY_BUTTON_X
;
1233 else if (strButton
.Equals("y")) buttonCode
= KEY_BUTTON_Y
;
1234 else if (strButton
.Equals("white")) buttonCode
= KEY_BUTTON_WHITE
;
1235 else if (strButton
.Equals("black")) buttonCode
= KEY_BUTTON_BLACK
;
1236 else if (strButton
.Equals("start")) buttonCode
= KEY_BUTTON_START
;
1237 else if (strButton
.Equals("back")) buttonCode
= KEY_BUTTON_BACK
;
1238 else if (strButton
.Equals("leftthumbbutton")) buttonCode
= KEY_BUTTON_LEFT_THUMB_BUTTON
;
1239 else if (strButton
.Equals("rightthumbbutton")) buttonCode
= KEY_BUTTON_RIGHT_THUMB_BUTTON
;
1240 else if (strButton
.Equals("leftthumbstick")) buttonCode
= KEY_BUTTON_LEFT_THUMB_STICK
;
1241 else if (strButton
.Equals("leftthumbstickup")) buttonCode
= KEY_BUTTON_LEFT_THUMB_STICK_UP
;
1242 else if (strButton
.Equals("leftthumbstickdown")) buttonCode
= KEY_BUTTON_LEFT_THUMB_STICK_DOWN
;
1243 else if (strButton
.Equals("leftthumbstickleft")) buttonCode
= KEY_BUTTON_LEFT_THUMB_STICK_LEFT
;
1244 else if (strButton
.Equals("leftthumbstickright")) buttonCode
= KEY_BUTTON_LEFT_THUMB_STICK_RIGHT
;
1245 else if (strButton
.Equals("rightthumbstick")) buttonCode
= KEY_BUTTON_RIGHT_THUMB_STICK
;
1246 else if (strButton
.Equals("rightthumbstickup")) buttonCode
= KEY_BUTTON_RIGHT_THUMB_STICK_UP
;
1247 else if (strButton
.Equals("rightthumbstickdown")) buttonCode
= KEY_BUTTON_RIGHT_THUMB_STICK_DOWN
;
1248 else if (strButton
.Equals("rightthumbstickleft")) buttonCode
= KEY_BUTTON_RIGHT_THUMB_STICK_LEFT
;
1249 else if (strButton
.Equals("rightthumbstickright")) buttonCode
= KEY_BUTTON_RIGHT_THUMB_STICK_RIGHT
;
1250 else if (strButton
.Equals("lefttrigger")) buttonCode
= KEY_BUTTON_LEFT_TRIGGER
;
1251 else if (strButton
.Equals("righttrigger")) buttonCode
= KEY_BUTTON_RIGHT_TRIGGER
;
1252 else if (strButton
.Equals("leftanalogtrigger")) buttonCode
= KEY_BUTTON_LEFT_ANALOG_TRIGGER
;
1253 else if (strButton
.Equals("rightanalogtrigger")) buttonCode
= KEY_BUTTON_RIGHT_ANALOG_TRIGGER
;
1254 else if (strButton
.Equals("dpadleft")) buttonCode
= KEY_BUTTON_DPAD_LEFT
;
1255 else if (strButton
.Equals("dpadright")) buttonCode
= KEY_BUTTON_DPAD_RIGHT
;
1256 else if (strButton
.Equals("dpadup")) buttonCode
= KEY_BUTTON_DPAD_UP
;
1257 else if (strButton
.Equals("dpaddown")) buttonCode
= KEY_BUTTON_DPAD_DOWN
;
1258 else CLog::Log(LOGERROR
, "Gamepad Translator: Can't find button %s", strButton
.c_str());
1262 uint32_t CButtonTranslator::TranslateRemoteString(const char *szButton
)
1266 uint32_t buttonCode
= 0;
1267 CStdString strButton
= szButton
;
1268 StringUtils::ToLower(strButton
);
1269 if (strButton
.Equals("left")) buttonCode
= XINPUT_IR_REMOTE_LEFT
;
1270 else if (strButton
.Equals("right")) buttonCode
= XINPUT_IR_REMOTE_RIGHT
;
1271 else if (strButton
.Equals("up")) buttonCode
= XINPUT_IR_REMOTE_UP
;
1272 else if (strButton
.Equals("down")) buttonCode
= XINPUT_IR_REMOTE_DOWN
;
1273 else if (strButton
.Equals("select")) buttonCode
= XINPUT_IR_REMOTE_SELECT
;
1274 else if (strButton
.Equals("back")) buttonCode
= XINPUT_IR_REMOTE_BACK
;
1275 else if (strButton
.Equals("menu")) buttonCode
= XINPUT_IR_REMOTE_MENU
;
1276 else if (strButton
.Equals("info")) buttonCode
= XINPUT_IR_REMOTE_INFO
;
1277 else if (strButton
.Equals("display")) buttonCode
= XINPUT_IR_REMOTE_DISPLAY
;
1278 else if (strButton
.Equals("title")) buttonCode
= XINPUT_IR_REMOTE_TITLE
;
1279 else if (strButton
.Equals("play")) buttonCode
= XINPUT_IR_REMOTE_PLAY
;
1280 else if (strButton
.Equals("pause")) buttonCode
= XINPUT_IR_REMOTE_PAUSE
;
1281 else if (strButton
.Equals("reverse")) buttonCode
= XINPUT_IR_REMOTE_REVERSE
;
1282 else if (strButton
.Equals("forward")) buttonCode
= XINPUT_IR_REMOTE_FORWARD
;
1283 else if (strButton
.Equals("skipplus")) buttonCode
= XINPUT_IR_REMOTE_SKIP_PLUS
;
1284 else if (strButton
.Equals("skipminus")) buttonCode
= XINPUT_IR_REMOTE_SKIP_MINUS
;
1285 else if (strButton
.Equals("stop")) buttonCode
= XINPUT_IR_REMOTE_STOP
;
1286 else if (strButton
.Equals("zero")) buttonCode
= XINPUT_IR_REMOTE_0
;
1287 else if (strButton
.Equals("one")) buttonCode
= XINPUT_IR_REMOTE_1
;
1288 else if (strButton
.Equals("two")) buttonCode
= XINPUT_IR_REMOTE_2
;
1289 else if (strButton
.Equals("three")) buttonCode
= XINPUT_IR_REMOTE_3
;
1290 else if (strButton
.Equals("four")) buttonCode
= XINPUT_IR_REMOTE_4
;
1291 else if (strButton
.Equals("five")) buttonCode
= XINPUT_IR_REMOTE_5
;
1292 else if (strButton
.Equals("six")) buttonCode
= XINPUT_IR_REMOTE_6
;
1293 else if (strButton
.Equals("seven")) buttonCode
= XINPUT_IR_REMOTE_7
;
1294 else if (strButton
.Equals("eight")) buttonCode
= XINPUT_IR_REMOTE_8
;
1295 else if (strButton
.Equals("nine")) buttonCode
= XINPUT_IR_REMOTE_9
;
1296 // additional keys from the media center extender for xbox remote
1297 else if (strButton
.Equals("power")) buttonCode
= XINPUT_IR_REMOTE_POWER
;
1298 else if (strButton
.Equals("mytv")) buttonCode
= XINPUT_IR_REMOTE_MY_TV
;
1299 else if (strButton
.Equals("mymusic")) buttonCode
= XINPUT_IR_REMOTE_MY_MUSIC
;
1300 else if (strButton
.Equals("mypictures")) buttonCode
= XINPUT_IR_REMOTE_MY_PICTURES
;
1301 else if (strButton
.Equals("myvideo")) buttonCode
= XINPUT_IR_REMOTE_MY_VIDEOS
;
1302 else if (strButton
.Equals("record")) buttonCode
= XINPUT_IR_REMOTE_RECORD
;
1303 else if (strButton
.Equals("start")) buttonCode
= XINPUT_IR_REMOTE_START
;
1304 else if (strButton
.Equals("volumeplus")) buttonCode
= XINPUT_IR_REMOTE_VOLUME_PLUS
;
1305 else if (strButton
.Equals("volumeminus")) buttonCode
= XINPUT_IR_REMOTE_VOLUME_MINUS
;
1306 else if (strButton
.Equals("channelplus")) buttonCode
= XINPUT_IR_REMOTE_CHANNEL_PLUS
;
1307 else if (strButton
.Equals("channelminus")) buttonCode
= XINPUT_IR_REMOTE_CHANNEL_MINUS
;
1308 else if (strButton
.Equals("pageplus")) buttonCode
= XINPUT_IR_REMOTE_CHANNEL_PLUS
;
1309 else if (strButton
.Equals("pageminus")) buttonCode
= XINPUT_IR_REMOTE_CHANNEL_MINUS
;
1310 else if (strButton
.Equals("mute")) buttonCode
= XINPUT_IR_REMOTE_MUTE
;
1311 else if (strButton
.Equals("recordedtv")) buttonCode
= XINPUT_IR_REMOTE_RECORDED_TV
;
1312 else if (strButton
.Equals("guide")) buttonCode
= XINPUT_IR_REMOTE_GUIDE
;
1313 else if (strButton
.Equals("livetv")) buttonCode
= XINPUT_IR_REMOTE_LIVE_TV
;
1314 else if (strButton
.Equals("liveradio")) buttonCode
= XINPUT_IR_REMOTE_LIVE_RADIO
;
1315 else if (strButton
.Equals("epgsearch")) buttonCode
= XINPUT_IR_REMOTE_EPG_SEARCH
;
1316 else if (strButton
.Equals("star")) buttonCode
= XINPUT_IR_REMOTE_STAR
;
1317 else if (strButton
.Equals("hash")) buttonCode
= XINPUT_IR_REMOTE_HASH
;
1318 else if (strButton
.Equals("clear")) buttonCode
= XINPUT_IR_REMOTE_CLEAR
;
1319 else if (strButton
.Equals("enter")) buttonCode
= XINPUT_IR_REMOTE_ENTER
;
1320 else if (strButton
.Equals("xbox")) buttonCode
= XINPUT_IR_REMOTE_DISPLAY
; // same as display
1321 else if (strButton
.Equals("playlist")) buttonCode
= XINPUT_IR_REMOTE_PLAYLIST
;
1322 else if (strButton
.Equals("guide")) buttonCode
= XINPUT_IR_REMOTE_GUIDE
;
1323 else if (strButton
.Equals("teletext")) buttonCode
= XINPUT_IR_REMOTE_TELETEXT
;
1324 else if (strButton
.Equals("red")) buttonCode
= XINPUT_IR_REMOTE_RED
;
1325 else if (strButton
.Equals("green")) buttonCode
= XINPUT_IR_REMOTE_GREEN
;
1326 else if (strButton
.Equals("yellow")) buttonCode
= XINPUT_IR_REMOTE_YELLOW
;
1327 else if (strButton
.Equals("blue")) buttonCode
= XINPUT_IR_REMOTE_BLUE
;
1328 else if (strButton
.Equals("subtitle")) buttonCode
= XINPUT_IR_REMOTE_SUBTITLE
;
1329 else if (strButton
.Equals("language")) buttonCode
= XINPUT_IR_REMOTE_LANGUAGE
;
1330 else CLog::Log(LOGERROR
, "Remote Translator: Can't find button %s", strButton
.c_str());
1334 uint32_t CButtonTranslator::TranslateUniversalRemoteString(const char *szButton
)
1336 if (!szButton
|| strlen(szButton
) < 4 || strnicmp(szButton
, "obc", 3))
1338 const char *szCode
= szButton
+ 3;
1339 // Button Code is 255 - OBC (Original Button Code) of the button
1340 uint32_t buttonCode
= 255 - atol(szCode
);
1341 if (buttonCode
> 255)
1346 uint32_t CButtonTranslator::TranslateKeyboardString(const char *szButton
)
1348 uint32_t buttonCode
= 0;
1349 XBMCKEYTABLE keytable
;
1351 // Look up the key name
1352 if (KeyTableLookupName(szButton
, &keytable
))
1354 buttonCode
= keytable
.vkey
;
1357 // The lookup failed i.e. the key name wasn't found
1360 CLog::Log(LOGERROR
, "Keyboard Translator: Can't find button %s", szButton
);
1363 buttonCode
|= KEY_VKEY
;
1368 uint32_t CButtonTranslator::TranslateKeyboardButton(TiXmlElement
*pButton
)
1370 uint32_t button_id
= 0;
1371 const char *szButton
= pButton
->Value();
1375 CStdString strKey
= szButton
;
1376 if (strKey
.Equals("key"))
1379 if (pButton
->QueryValueAttribute("id", &strID
) == TIXML_SUCCESS
)
1381 const char *str
= strID
.c_str();
1383 long int id
= strtol(str
, &endptr
, 0);
1384 if (endptr
- str
!= (int)strlen(str
) || id
<= 0 || id
> 0x00FFFFFF)
1385 CLog::Log(LOGDEBUG
, "%s - invalid key id %s", __FUNCTION__
, strID
.c_str());
1387 button_id
= (uint32_t) id
;
1390 CLog::Log(LOGERROR
, "Keyboard Translator: `key' button has no id");
1393 button_id
= TranslateKeyboardString(szButton
);
1395 // Process the ctrl/shift/alt modifiers
1397 if (pButton
->QueryValueAttribute("mod", &strMod
) == TIXML_SUCCESS
)
1399 StringUtils::ToLower(strMod
);
1401 CStdStringArray modArray
;
1402 StringUtils::SplitString(strMod
, ",", modArray
);
1403 for (unsigned int i
= 0; i
< modArray
.size(); i
++)
1405 CStdString
& substr
= modArray
[i
];
1406 StringUtils::Trim(substr
);
1408 if (substr
== "ctrl" || substr
== "control")
1409 button_id
|= CKey::MODIFIER_CTRL
;
1410 else if (substr
== "shift")
1411 button_id
|= CKey::MODIFIER_SHIFT
;
1412 else if (substr
== "alt")
1413 button_id
|= CKey::MODIFIER_ALT
;
1414 else if (substr
== "super" || substr
== "win")
1415 button_id
|= CKey::MODIFIER_SUPER
;
1416 else if (substr
== "meta" || substr
== "cmd")
1417 button_id
|= CKey::MODIFIER_META
;
1419 CLog::Log(LOGERROR
, "Keyboard Translator: Unknown key modifier %s in %s", substr
.c_str(), strMod
.c_str());
1426 uint32_t CButtonTranslator::TranslateAppCommand(const char *szButton
)
1428 #ifdef TARGET_WINDOWS
1429 CStdString strAppCommand
= szButton
;
1430 StringUtils::ToLower(strAppCommand
);
1432 for (int i
= 0; i
< sizeof(appcommands
)/sizeof(appcommands
[0]); i
++)
1433 if (strAppCommand
.Equals(appcommands
[i
].name
))
1434 return appcommands
[i
].action
| KEY_APPCOMMAND
;
1436 CLog::Log(LOGERROR
, "%s: Can't find appcommand %s", __FUNCTION__
, szButton
);
1442 uint32_t CButtonTranslator::TranslateMouseCommand(const char *szButton
)
1444 CStdString strMouseCommand
= szButton
;
1445 StringUtils::ToLower(strMouseCommand
);
1447 for (unsigned int i
= 0; i
< sizeof(mousecommands
)/sizeof(mousecommands
[0]); i
++)
1448 if (strMouseCommand
.Equals(mousecommands
[i
].name
))
1449 return mousecommands
[i
].action
| KEY_MOUSE
;
1451 CLog::Log(LOGERROR
, "%s: Can't find mouse command %s", __FUNCTION__
, szButton
);
1456 void CButtonTranslator::Clear()
1458 m_translatorMap
.clear();
1459 #if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
1460 ClearLircButtonMapEntries();
1461 lircRemotesMap
.clear();
1464 #if defined(HAS_SDL_JOYSTICK) || defined(HAS_EVENT_SERVER)
1465 m_joystickButtonMap
.clear();
1466 m_joystickAxisMap
.clear();
1467 m_joystickHatMap
.clear();
1473 uint32_t CButtonTranslator::TranslateTouchCommand(TiXmlElement
*pButton
, CButtonAction
&action
)
1475 const char *szButton
= pButton
->Value();
1476 if (szButton
== NULL
|| pButton
->FirstChild() == NULL
)
1479 const char *szAction
= pButton
->FirstChild()->Value();
1480 if (szAction
== NULL
)
1483 CStdString strTouchCommand
= szButton
;
1484 StringUtils::ToLower(strTouchCommand
);
1486 const char *attrVal
= pButton
->Attribute("direction");
1487 if (attrVal
!= NULL
)
1488 strTouchCommand
+= attrVal
;
1490 uint32_t actionId
= ACTION_NONE
;
1491 for (unsigned int i
= 0; i
< sizeof(touchcommands
)/sizeof(touchcommands
[0]); i
++)
1493 if (strTouchCommand
.Equals(touchcommands
[i
].name
))
1495 actionId
= touchcommands
[i
].action
;
1500 if (actionId
<= ACTION_NONE
)
1502 CLog::Log(LOGERROR
, "%s: Can't find touch command %s", __FUNCTION__
, szButton
);
1506 attrVal
= pButton
->Attribute("pointers");
1507 if (attrVal
!= NULL
)
1509 int pointers
= (int)strtol(attrVal
, NULL
, 0);
1511 actionId
+= pointers
- 1;
1514 action
.strID
= szAction
;
1515 if (!TranslateActionString(szAction
, action
.id
) || action
.id
<= ACTION_NONE
)
1518 return actionId
| KEY_TOUCH
;
1521 void CButtonTranslator::MapTouchActions(int windowID
, TiXmlNode
*pTouch
)
1527 // check if there already is a touch map for the window ID
1528 std::map
<int, buttonMap
>::iterator it
= m_touchMap
.find(windowID
);
1529 if (it
!= m_touchMap
.end())
1531 // get the existing touch map and remove it from the window mapping
1532 // as it will be inserted later on
1534 m_touchMap
.erase(it
);
1537 uint32_t actionId
= 0;
1538 TiXmlElement
*pTouchElem
= pTouch
->ToElement();
1539 if (pTouchElem
== NULL
)
1542 TiXmlElement
*pButton
= pTouchElem
->FirstChildElement();
1543 while (pButton
!= NULL
)
1545 CButtonAction action
;
1546 actionId
= TranslateTouchCommand(pButton
, action
);
1549 // check if there already is a mapping for the parsed action
1550 // and remove it if necessary
1551 buttonMap::iterator actionIt
= map
.find(actionId
);
1552 if (actionIt
!= map
.end())
1553 map
.erase(actionIt
);
1555 map
.insert(std::make_pair(actionId
, action
));
1558 pButton
= pButton
->NextSiblingElement();
1561 // add the modified touch map with the window ID
1563 m_touchMap
.insert(std::pair
<int, buttonMap
>(windowID
, map
));
1566 int CButtonTranslator::GetTouchActionCode(int window
, int action
)
1568 std::map
<int, buttonMap
>::const_iterator windowIt
= m_touchMap
.find(window
);
1569 if (windowIt
== m_touchMap
.end())
1572 buttonMap::const_iterator touchIt
= windowIt
->second
.find(action
);
1573 if (touchIt
== windowIt
->second
.end())
1576 return touchIt
->second
.id
;