1 /*****************************************************************************
2 * actions.c: handle vlc actions
3 *****************************************************************************
4 * Copyright (C) 2003-2016 VLC authors and VideoLAN
6 * Authors: Sigmund Augdal Helberg <dnumgis@videolan.org>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
29 * This file defines functions and structures for hotkey handling in vlc
40 #include <vlc_common.h>
41 #include <vlc_actions.h>
42 #include <vlc_charset.h>
43 #include "config/configuration.h"
46 static const struct key_descriptor
51 { /* Alphabetical order */
52 { N_("Backspace"), KEY_BACKSPACE
},
53 { N_("Brightness Down"), KEY_BRIGHTNESS_DOWN
},
54 { N_("Brightness Up"), KEY_BRIGHTNESS_UP
},
55 { N_("Browser Back"), KEY_BROWSER_BACK
},
56 { N_("Browser Favorites"), KEY_BROWSER_FAVORITES
},
57 { N_("Browser Forward"), KEY_BROWSER_FORWARD
},
58 { N_("Browser Home"), KEY_BROWSER_HOME
},
59 { N_("Browser Refresh"), KEY_BROWSER_REFRESH
},
60 { N_("Browser Search"), KEY_BROWSER_SEARCH
},
61 { N_("Browser Stop"), KEY_BROWSER_STOP
},
62 { N_("Delete"), KEY_DELETE
},
63 { N_("Down"), KEY_DOWN
},
64 { N_("End"), KEY_END
},
65 { N_("Enter"), KEY_ENTER
},
66 { N_("Esc"), KEY_ESC
},
68 { N_("F10"), KEY_F10
},
69 { N_("F11"), KEY_F11
},
70 { N_("F12"), KEY_F12
},
79 { N_("Home"), KEY_HOME
},
80 { N_("Insert"), KEY_INSERT
},
81 { N_("Left"), KEY_LEFT
},
82 { N_("Media Angle"), KEY_MEDIA_ANGLE
},
83 { N_("Media Audio Track"), KEY_MEDIA_AUDIO
},
84 { N_("Media Forward"), KEY_MEDIA_FORWARD
},
85 { N_("Media Menu"), KEY_MEDIA_MENU
},
86 { N_("Media Next Frame"), KEY_MEDIA_FRAME_NEXT
},
87 { N_("Media Next Track"), KEY_MEDIA_NEXT_TRACK
},
88 { N_("Media Play Pause"), KEY_MEDIA_PLAY_PAUSE
},
89 { N_("Media Prev Frame"), KEY_MEDIA_FRAME_PREV
},
90 { N_("Media Prev Track"), KEY_MEDIA_PREV_TRACK
},
91 { N_("Media Record"), KEY_MEDIA_RECORD
},
92 { N_("Media Repeat"), KEY_MEDIA_REPEAT
},
93 { N_("Media Rewind"), KEY_MEDIA_REWIND
},
94 { N_("Media Select"), KEY_MEDIA_SELECT
},
95 { N_("Media Shuffle"), KEY_MEDIA_SHUFFLE
},
96 { N_("Media Stop"), KEY_MEDIA_STOP
},
97 { N_("Media Subtitle"), KEY_MEDIA_SUBTITLE
},
98 { N_("Media Time"), KEY_MEDIA_TIME
},
99 { N_("Media View"), KEY_MEDIA_VIEW
},
100 { N_("Menu"), KEY_MENU
},
101 { N_("Mouse Wheel Down"), KEY_MOUSEWHEELDOWN
},
102 { N_("Mouse Wheel Left"), KEY_MOUSEWHEELLEFT
},
103 { N_("Mouse Wheel Right"), KEY_MOUSEWHEELRIGHT
},
104 { N_("Mouse Wheel Up"), KEY_MOUSEWHEELUP
},
105 { N_("Page Down"), KEY_PAGEDOWN
},
106 { N_("Page Up"), KEY_PAGEUP
},
107 { N_("Pause"), KEY_PAUSE
},
108 { N_("Print"), KEY_PRINT
},
109 { N_("Right"), KEY_RIGHT
},
110 { N_("Space"), ' ' },
111 { N_("Tab"), KEY_TAB
},
112 { N_("Unset"), KEY_UNSET
},
113 { N_("Up"), KEY_UP
},
114 { N_("Volume Down"), KEY_VOLUME_DOWN
},
115 { N_("Volume Mute"), KEY_VOLUME_MUTE
},
116 { N_("Volume Up"), KEY_VOLUME_UP
},
117 { N_("Zoom In"), KEY_ZOOM_IN
},
118 { N_("Zoom Out"), KEY_ZOOM_OUT
},
120 #define KEYS_COUNT (sizeof(s_keys)/sizeof(s_keys[0]))
122 static int keystrcmp (const void *key
, const void *elem
)
124 const char *sa
= key
, *sb
= elem
;
125 return strcmp (sa
, sb
);
128 /* Convert Unicode code point to UTF-8 */
129 static char *utf8_cp (uint_fast32_t cp
, char *buf
)
136 else if (cp
< (1 << 11))
139 buf
[1] = 0x80 | (cp
& 0x3F);
143 else if (cp
< (1 << 16))
146 buf
[2] = 0x80 | (cp
& 0x3F);
148 buf
[1] = 0x80 | (cp
& 0x3F);
152 else if (cp
< (1 << 21))
155 buf
[3] = 0x80 | (cp
& 0x3F);
157 buf
[2] = 0x80 | (cp
& 0x3F);
159 buf
[1] = 0x80 | (cp
& 0x3F);
169 * Parse a human-readable string representation of a VLC key code.
170 * @note This only works with the American English representation
171 * (a.k.a. C or POSIX), not with the local representation returned from
173 * @return a VLC key code, or KEY_UNSET on failure.
175 uint_fast32_t vlc_str2keycode (const char *name
)
177 uint_fast32_t mods
= 0;
182 size_t len
= strcspn (name
, "-+");
183 if (len
== 0 || name
[len
] == '\0')
186 if (len
== 4 && !strncasecmp (name
, "Ctrl", 4))
187 mods
|= KEY_MODIFIER_CTRL
;
188 if (len
== 3 && !strncasecmp (name
, "Alt", 3))
189 mods
|= KEY_MODIFIER_ALT
;
190 if (len
== 5 && !strncasecmp (name
, "Shift", 5))
191 mods
|= KEY_MODIFIER_SHIFT
;
192 if (len
== 4 && !strncasecmp (name
, "Meta", 4))
193 mods
|= KEY_MODIFIER_META
;
194 if (len
== 7 && !strncasecmp (name
, "Command", 7))
195 mods
|= KEY_MODIFIER_COMMAND
;
200 struct key_descriptor
*d
= bsearch (name
, s_keys
, KEYS_COUNT
,
201 sizeof (s_keys
[0]), keystrcmp
);
205 if (vlc_towc (name
, &code
) <= 0)
208 if (code
!= KEY_UNSET
)
213 static char *nooptext (const char *txt
)
219 * Format a human-readable and unique representation of a VLC key code
220 * (including modifiers).
221 * @param code key code to translate to a string
222 * @param locale true to get a localized string,
223 * false to get a C string suitable for 'vlcrc'
224 * @return a heap-allocated string, or NULL on error.
226 char *vlc_keycode2str (uint_fast32_t code
, bool locale
)
228 char *(*tr
) (const char *) = locale
? vlc_gettext
: nooptext
;
231 uintptr_t key
= code
& ~KEY_MODIFIER
;
233 for (size_t i
= 0; i
< KEYS_COUNT
; i
++)
234 if (s_keys
[i
].i_code
== key
)
236 name
= s_keys
[i
].psz
;
240 if (utf8_cp (key
, buf
) == NULL
)
245 if (asprintf (&str
, "%s%s%s%s%s%s",
246 (code
& KEY_MODIFIER_CTRL
) ? tr(N_("Ctrl+")) : "",
247 (code
& KEY_MODIFIER_ALT
) ? tr(N_("Alt+")) : "",
248 (code
& KEY_MODIFIER_SHIFT
) ? tr(N_("Shift+")) : "",
249 (code
& KEY_MODIFIER_META
) ? tr(N_("Meta+")) : "",
250 (code
& KEY_MODIFIER_COMMAND
) ? tr(N_("Command+")) : "",
257 /*** VLC key map ***/
260 static const struct name2action
264 } s_names2actions
[] =
266 /* *MUST* be sorted (ASCII order) */
267 { "aspect-ratio", ACTIONID_ASPECT_RATIO
, },
268 { "audio-track", ACTIONID_AUDIO_TRACK
, },
269 { "audiodelay-down", ACTIONID_AUDIODELAY_DOWN
, },
270 { "audiodelay-up", ACTIONID_AUDIODELAY_UP
, },
271 { "audiodevice-cycle", ACTIONID_AUDIODEVICE_CYCLE
, },
272 { "chapter-next", ACTIONID_CHAPTER_NEXT
, },
273 { "chapter-prev", ACTIONID_CHAPTER_PREV
, },
274 { "clear-playlist", ACTIONID_PLAY_CLEAR
, },
275 { "crop", ACTIONID_CROP
, },
276 { "crop-bottom", ACTIONID_CROP_BOTTOM
, },
277 { "crop-left", ACTIONID_CROP_LEFT
, },
278 { "crop-right", ACTIONID_CROP_RIGHT
, },
279 { "crop-top", ACTIONID_CROP_TOP
, },
280 { "decr-scalefactor", ACTIONID_SCALE_DOWN
, },
281 { "deinterlace", ACTIONID_DEINTERLACE
, },
282 { "deinterlace-mode", ACTIONID_DEINTERLACE_MODE
, },
283 { "disc-menu", ACTIONID_DISC_MENU
, },
284 { "faster", ACTIONID_FASTER
, },
285 { "frame-next", ACTIONID_FRAME_NEXT
, },
286 { "incr-scalefactor", ACTIONID_SCALE_UP
, },
287 { "intf-boss", ACTIONID_INTF_BOSS
, },
288 { "intf-popup-menu", ACTIONID_INTF_POPUP_MENU
, },
289 { "intf-show", ACTIONID_INTF_TOGGLE_FSC
, },
290 { "jump+extrashort", ACTIONID_JUMP_FORWARD_EXTRASHORT
, },
291 { "jump+long", ACTIONID_JUMP_FORWARD_LONG
, },
292 { "jump+medium", ACTIONID_JUMP_FORWARD_MEDIUM
, },
293 { "jump+short", ACTIONID_JUMP_FORWARD_SHORT
, },
294 { "jump-extrashort", ACTIONID_JUMP_BACKWARD_EXTRASHORT
, },
295 { "jump-long", ACTIONID_JUMP_BACKWARD_LONG
, },
296 { "jump-medium", ACTIONID_JUMP_BACKWARD_MEDIUM
, },
297 { "jump-short", ACTIONID_JUMP_BACKWARD_SHORT
, },
298 { "leave-fullscreen", ACTIONID_LEAVE_FULLSCREEN
, },
299 { "loop", ACTIONID_LOOP
, },
300 { "nav-activate", ACTIONID_NAV_ACTIVATE
, },
301 { "nav-down", ACTIONID_NAV_DOWN
, },
302 { "nav-left", ACTIONID_NAV_LEFT
, },
303 { "nav-right", ACTIONID_NAV_RIGHT
, },
304 { "nav-up", ACTIONID_NAV_UP
, },
305 { "next", ACTIONID_NEXT
, },
306 { "pause", ACTIONID_PAUSE
, },
307 { "play", ACTIONID_PLAY
, },
308 { "play-bookmark1", ACTIONID_PLAY_BOOKMARK1
, },
309 { "play-bookmark10", ACTIONID_PLAY_BOOKMARK10
, },
310 { "play-bookmark2", ACTIONID_PLAY_BOOKMARK2
, },
311 { "play-bookmark3", ACTIONID_PLAY_BOOKMARK3
, },
312 { "play-bookmark4", ACTIONID_PLAY_BOOKMARK4
, },
313 { "play-bookmark5", ACTIONID_PLAY_BOOKMARK5
, },
314 { "play-bookmark6", ACTIONID_PLAY_BOOKMARK6
, },
315 { "play-bookmark7", ACTIONID_PLAY_BOOKMARK7
, },
316 { "play-bookmark8", ACTIONID_PLAY_BOOKMARK8
, },
317 { "play-bookmark9", ACTIONID_PLAY_BOOKMARK9
, },
318 { "play-pause", ACTIONID_PLAY_PAUSE
, },
319 { "position", ACTIONID_POSITION
, },
320 { "prev", ACTIONID_PREV
, },
321 { "program-sid-next", ACTIONID_PROGRAM_SID_NEXT
, },
322 { "program-sid-prev", ACTIONID_PROGRAM_SID_PREV
, },
323 { "quit", ACTIONID_QUIT
, },
324 { "random", ACTIONID_RANDOM
, },
325 { "rate-faster-fine", ACTIONID_RATE_FASTER_FINE
, },
326 { "rate-normal", ACTIONID_RATE_NORMAL
, },
327 { "rate-slower-fine", ACTIONID_RATE_SLOWER_FINE
, },
328 { "record", ACTIONID_RECORD
, },
329 { "set-bookmark1", ACTIONID_SET_BOOKMARK1
, },
330 { "set-bookmark10", ACTIONID_SET_BOOKMARK10
, },
331 { "set-bookmark2", ACTIONID_SET_BOOKMARK2
, },
332 { "set-bookmark3", ACTIONID_SET_BOOKMARK3
, },
333 { "set-bookmark4", ACTIONID_SET_BOOKMARK4
, },
334 { "set-bookmark5", ACTIONID_SET_BOOKMARK5
, },
335 { "set-bookmark6", ACTIONID_SET_BOOKMARK6
, },
336 { "set-bookmark7", ACTIONID_SET_BOOKMARK7
, },
337 { "set-bookmark8", ACTIONID_SET_BOOKMARK8
, },
338 { "set-bookmark9", ACTIONID_SET_BOOKMARK9
, },
339 { "slower", ACTIONID_SLOWER
, },
340 { "snapshot", ACTIONID_SNAPSHOT
, },
341 { "stop", ACTIONID_STOP
, },
342 { "subdelay-down", ACTIONID_SUBDELAY_DOWN
, },
343 { "subdelay-up", ACTIONID_SUBDELAY_UP
, },
344 { "subpos-down", ACTIONID_SUBPOS_DOWN
, },
345 { "subpos-up", ACTIONID_SUBPOS_UP
, },
346 { "subsync-apply", ACTIONID_SUBSYNC_APPLY
, },
347 { "subsync-markaudio", ACTIONID_SUBSYNC_MARKAUDIO
, },
348 { "subsync-marksub", ACTIONID_SUBSYNC_MARKSUB
, },
349 { "subsync-reset", ACTIONID_SUBSYNC_RESET
, },
350 { "subtitle-revtrack", ACTIONID_SUBTITLE_REVERSE_TRACK
, },
351 { "subtitle-text-scale-down", ACTIONID_SUBTITLE_TEXT_SCALE_DOWN
, },
352 { "subtitle-text-scale-normal", ACTIONID_SUBTITLE_TEXT_SCALE_NORMAL
, },
353 { "subtitle-text-scale-up", ACTIONID_SUBTITLE_TEXT_SCALE_UP
, },
354 { "subtitle-toggle", ACTIONID_SUBTITLE_TOGGLE
, },
355 { "subtitle-track", ACTIONID_SUBTITLE_TRACK
, },
356 { "title-next", ACTIONID_TITLE_NEXT
, },
357 { "title-prev", ACTIONID_TITLE_PREV
, },
358 { "toggle-autoscale", ACTIONID_TOGGLE_AUTOSCALE
, },
359 { "toggle-fullscreen", ACTIONID_TOGGLE_FULLSCREEN
, },
360 { "uncrop-bottom", ACTIONID_UNCROP_BOTTOM
, },
361 { "uncrop-left", ACTIONID_UNCROP_LEFT
, },
362 { "uncrop-right", ACTIONID_UNCROP_RIGHT
, },
363 { "uncrop-top", ACTIONID_UNCROP_TOP
, },
364 { "unzoom", ACTIONID_UNZOOM
, },
365 { "viewpoint-fov-in", ACTIONID_VIEWPOINT_FOV_IN
, },
366 { "viewpoint-fov-out", ACTIONID_VIEWPOINT_FOV_OUT
, },
367 { "viewpoint-roll-anticlock", ACTIONID_VIEWPOINT_ROLL_ANTICLOCK
, },
368 { "viewpoint-roll-clock", ACTIONID_VIEWPOINT_ROLL_CLOCK
, },
369 { "vol-down", ACTIONID_VOL_DOWN
, },
370 { "vol-mute", ACTIONID_VOL_MUTE
, },
371 { "vol-up", ACTIONID_VOL_UP
, },
372 { "wallpaper", ACTIONID_WALLPAPER
, },
373 { "zoom", ACTIONID_ZOOM
, },
374 { "zoom-double", ACTIONID_ZOOM_DOUBLE
, },
375 { "zoom-half", ACTIONID_ZOOM_HALF
, },
376 { "zoom-original", ACTIONID_ZOOM_ORIGINAL
, },
377 { "zoom-quarter", ACTIONID_ZOOM_QUARTER
, },
379 #define ACTIONS_COUNT (sizeof (s_names2actions) / sizeof (s_names2actions[0]))
383 uint32_t key
; ///< Key code
384 vlc_action_id_t action
; ///< Action ID
387 static int keycmp (const void *a
, const void *b
)
389 const struct mapping
*ka
= a
, *kb
= b
;
391 return (ka
->key
< kb
->key
) ? -1 : (ka
->key
> kb
->key
) ? +1 : 0;
396 void *map
; /* Key map */
397 void *global_map
; /* Grabbed/global key map */
398 const char *ppsz_keys
[];
401 static int vlc_key_to_action (vlc_object_t
*obj
, const char *varname
,
402 vlc_value_t prevkey
, vlc_value_t curkey
, void *d
)
404 void *const *map
= d
;
405 const struct mapping
**pent
;
406 uint32_t keycode
= curkey
.i_int
;
408 pent
= tfind (&keycode
, map
, keycmp
);
414 return var_SetInteger (obj
, "key-action", (*pent
)->action
);
418 * Adds a mapping from a certain key code to a certain action.
420 static int add_mapping (void **map
, uint32_t keycode
, vlc_action_id_t action
)
422 struct mapping
*entry
= malloc (sizeof (*entry
));
425 entry
->key
= keycode
;
426 entry
->action
= action
;
428 struct mapping
**pent
= tsearch (entry
, map
, keycmp
);
429 if (unlikely(pent
== NULL
))
439 static void add_wheel_mapping (void **map
, uint32_t kmore
, uint32_t kless
,
442 vlc_action_id_t amore
= ACTIONID_NONE
, aless
= ACTIONID_NONE
;
446 case 0: /* volume up/down */
447 amore
= ACTIONID_COMBO_VOL_FOV_UP
;
448 aless
= ACTIONID_COMBO_VOL_FOV_DOWN
;
450 case 2: /* position latter/earlier */
451 amore
= ACTIONID_JUMP_FORWARD_EXTRASHORT
;
452 aless
= ACTIONID_JUMP_BACKWARD_EXTRASHORT
;
454 case 3: /* position earlier/latter */
455 amore
= ACTIONID_JUMP_BACKWARD_EXTRASHORT
;
456 aless
= ACTIONID_JUMP_FORWARD_EXTRASHORT
;
460 if (amore
!= ACTIONID_NONE
)
461 add_mapping (map
, kmore
, amore
);
462 if (aless
!= ACTIONID_NONE
)
463 add_mapping (map
, kless
, aless
);
468 * Sets up all key mappings for a given action.
469 * \param map tree (of struct mapping entries) to write mappings to
470 * \param confname VLC configuration item to read mappings from
471 * \param action action ID
473 static void init_action (vlc_object_t
*obj
, void **map
,
474 const char *confname
, vlc_action_id_t action
)
476 char *keys
= var_InheritString (obj
, confname
);
480 for (char *buf
, *key
= strtok_r (keys
, "\t", &buf
);
482 key
= strtok_r (NULL
, "\t", &buf
))
484 uint32_t code
= vlc_str2keycode (key
);
485 if (code
== KEY_UNSET
)
487 msg_Warn (obj
, "Key \"%s\" unrecognized", key
);
491 if (add_mapping (map
, code
, action
) == EEXIST
)
492 msg_Warn (obj
, "Key \"%s\" bound to multiple actions", key
);
498 * Initializes the key map from configuration.
500 int libvlc_InternalActionsInit (libvlc_int_t
*libvlc
)
502 assert(libvlc
!= NULL
);
504 vlc_object_t
*obj
= VLC_OBJECT(libvlc
);
505 vlc_actions_t
*as
= malloc (sizeof (*as
) + (1 + ACTIONS_COUNT
)
506 * sizeof (*as
->ppsz_keys
));
508 if (unlikely(as
== NULL
))
511 as
->global_map
= NULL
;
513 var_Create (obj
, "key-pressed", VLC_VAR_INTEGER
);
514 var_Create (obj
, "global-key-pressed", VLC_VAR_INTEGER
);
515 var_Create (obj
, "key-action", VLC_VAR_INTEGER
);
517 /* Initialize from configuration */
518 for (size_t i
= 0; i
< ACTIONS_COUNT
; i
++)
522 && strcmp (s_names2actions
[i
-1].psz
, s_names2actions
[i
].psz
) >= 0)
524 msg_Err (libvlc
, "key-%s and key-%s are not ordered properly",
525 s_names2actions
[i
-1].psz
, s_names2actions
[i
].psz
);
529 as
->ppsz_keys
[i
] = s_names2actions
[i
].psz
;
531 char name
[12 + MAXACTION
];
533 snprintf (name
, sizeof (name
), "global-key-%s", s_names2actions
[i
].psz
);
534 init_action (obj
, &as
->map
, name
+ 7, s_names2actions
[i
].id
);
535 init_action (obj
, &as
->global_map
, name
, s_names2actions
[i
].id
);
537 as
->ppsz_keys
[ACTIONS_COUNT
] = NULL
;
539 /* Initialize mouse wheel events */
540 add_wheel_mapping (&as
->map
, KEY_MOUSEWHEELRIGHT
, KEY_MOUSEWHEELLEFT
,
541 var_InheritInteger (obj
, "hotkeys-x-wheel-mode"));
542 add_wheel_mapping (&as
->map
, KEY_MOUSEWHEELUP
, KEY_MOUSEWHEELDOWN
,
543 var_InheritInteger (obj
, "hotkeys-y-wheel-mode"));
545 libvlc_priv(libvlc
)->actions
= as
;
546 var_AddCallback (obj
, "key-pressed", vlc_key_to_action
, &as
->map
);
547 var_AddCallback (obj
, "global-key-pressed", vlc_key_to_action
,
553 * Destroys the key map.
555 void libvlc_InternalActionsClean (libvlc_int_t
*libvlc
)
557 assert(libvlc
!= NULL
);
559 vlc_actions_t
*as
= libvlc_priv(libvlc
)->actions
;
560 if (unlikely(as
== NULL
))
563 var_DelCallback (libvlc
, "global-key-pressed", vlc_key_to_action
,
565 var_DelCallback (libvlc
, "key-pressed", vlc_key_to_action
, &as
->map
);
567 tdestroy (as
->global_map
, free
);
568 tdestroy (as
->map
, free
);
570 libvlc_priv(libvlc
)->actions
= NULL
;
574 static int actcmp(const void *key
, const void *ent
)
576 const struct name2action
*act
= ent
;
577 return strcmp(key
, act
->psz
);
581 * Get the action ID from the action name in the configuration subsystem.
582 * @return the action ID or ACTIONID_NONE on error.
585 vlc_actions_get_id (const char *name
)
587 const struct name2action
*act
;
589 if (strncmp (name
, "key-", 4))
590 return ACTIONID_NONE
;
593 act
= bsearch(name
, s_names2actions
, ACTIONS_COUNT
, sizeof(*act
), actcmp
);
594 return (act
!= NULL
) ? act
->id
: ACTIONID_NONE
;
597 #undef vlc_actions_get_keycodes
599 vlc_actions_get_keycodes(vlc_object_t
*p_obj
, const char *psz_key_name
,
600 bool b_global
, uint_fast32_t **pp_keycodes
)
602 char varname
[12 /* "global-key-" */ + strlen( psz_key_name
)];
603 sprintf( varname
, "%skey-%s", b_global
? "global-" : "", psz_key_name
);
607 char *psz_keys
= var_InheritString( p_obj
, varname
);
608 if( psz_keys
== NULL
)
611 size_t i_nb_keycodes
= 0;
612 for( const char* psz_it
= psz_keys
; *psz_it
; ++psz_it
)
614 if( *psz_it
== '\t' )
618 *pp_keycodes
= malloc( i_nb_keycodes
* sizeof( **pp_keycodes
) );
619 if( unlikely( !*pp_keycodes
) )
625 for( char *buf
, *key
= strtok_r( psz_keys
, "\t", &buf
);
627 key
= strtok_r( NULL
, "\t", &buf
), ++i
)
629 (*pp_keycodes
)[i
] = vlc_str2keycode( key
);
631 assert( i
== i_nb_keycodes
);
633 return i_nb_keycodes
;
636 #undef vlc_actions_get_key_names
638 vlc_actions_get_key_names(vlc_object_t
*p_obj
)
640 vlc_actions_t
*as
= libvlc_priv(p_obj
->obj
.libvlc
)->actions
;
641 return as
->ppsz_keys
;