]> git.sesse.net Git - vlc/blob - src/config/keys.c
codec: dts: fix custom channel mapping detection/tautology
[vlc] / src / config / keys.c
1 /*****************************************************************************
2  * keys.c: keys configuration
3  *****************************************************************************
4  * Copyright (C) 2003-2009 VLC authors and VideoLAN
5  *
6  * Authors: Sigmund Augdal Helberg <dnumgis@videolan.org>
7  *
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.
12  *
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.
17  *
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  *****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 /**
28  * \file
29  * This file defines functions and structures for hotkey handling in vlc
30  */
31
32 #ifdef HAVE_CONFIG_H
33 # include <config.h>
34 #endif
35
36 #include <stdlib.h>
37 #include <limits.h>
38 #ifdef HAVE_SEARCH_H
39 # include <search.h>
40 #endif
41 #include <errno.h>
42
43 #include <vlc_common.h>
44 #include <vlc_keys.h>
45 #include "configuration.h"
46 #include "libvlc.h"
47
48 typedef struct key_descriptor_s
49 {
50     const char psz_key_string[20];
51     uint32_t i_key_code;
52 } key_descriptor_t;
53
54 static const struct key_descriptor_s vlc_keys[] =
55 {   /* Alphabetical order */
56     { N_("Backspace"),         KEY_BACKSPACE         },
57     { N_("Brightness Down"),   KEY_BRIGHTNESS_DOWN   },
58     { N_("Brightness Up"),     KEY_BRIGHTNESS_UP     },
59     { N_("Browser Back"),      KEY_BROWSER_BACK      },
60     { N_("Browser Favorites"), KEY_BROWSER_FAVORITES },
61     { N_("Browser Forward"),   KEY_BROWSER_FORWARD   },
62     { N_("Browser Home"),      KEY_BROWSER_HOME      },
63     { N_("Browser Refresh"),   KEY_BROWSER_REFRESH   },
64     { N_("Browser Search"),    KEY_BROWSER_SEARCH    },
65     { N_("Browser Stop"),      KEY_BROWSER_STOP      },
66     { N_("Delete"),            KEY_DELETE            },
67     { N_("Down"),              KEY_DOWN              },
68     { N_("End"),               KEY_END               },
69     { N_("Enter"),             KEY_ENTER             },
70     { N_("Esc"),               KEY_ESC               },
71     { N_("F1"),                KEY_F1                },
72     { N_("F10"),               KEY_F10               },
73     { N_("F11"),               KEY_F11               },
74     { N_("F12"),               KEY_F12               },
75     { N_("F2"),                KEY_F2                },
76     { N_("F3"),                KEY_F3                },
77     { N_("F4"),                KEY_F4                },
78     { N_("F5"),                KEY_F5                },
79     { N_("F6"),                KEY_F6                },
80     { N_("F7"),                KEY_F7                },
81     { N_("F8"),                KEY_F8                },
82     { N_("F9"),                KEY_F9                },
83     { N_("Home"),              KEY_HOME              },
84     { N_("Insert"),            KEY_INSERT            },
85     { N_("Left"),              KEY_LEFT              },
86     { N_("Media Angle"),       KEY_MEDIA_ANGLE       },
87     { N_("Media Audio Track"), KEY_MEDIA_AUDIO       },
88     { N_("Media Forward"),     KEY_MEDIA_FORWARD     },
89     { N_("Media Menu"),        KEY_MEDIA_MENU        },
90     { N_("Media Next Frame"),  KEY_MEDIA_FRAME_NEXT  },
91     { N_("Media Next Track"),  KEY_MEDIA_NEXT_TRACK  },
92     { N_("Media Play Pause"),  KEY_MEDIA_PLAY_PAUSE  },
93     { N_("Media Prev Frame"),  KEY_MEDIA_FRAME_PREV  },
94     { N_("Media Prev Track"),  KEY_MEDIA_PREV_TRACK  },
95     { N_("Media Record"),      KEY_MEDIA_RECORD      },
96     { N_("Media Repeat"),      KEY_MEDIA_REPEAT      },
97     { N_("Media Rewind"),      KEY_MEDIA_REWIND      },
98     { N_("Media Select"),      KEY_MEDIA_SELECT      },
99     { N_("Media Shuffle"),     KEY_MEDIA_SHUFFLE     },
100     { N_("Media Stop"),        KEY_MEDIA_STOP        },
101     { N_("Media Subtitle"),    KEY_MEDIA_SUBTITLE    },
102     { N_("Media Time"),        KEY_MEDIA_TIME        },
103     { N_("Media View"),        KEY_MEDIA_VIEW        },
104     { N_("Menu"),              KEY_MENU              },
105     { N_("Mouse Wheel Down"),  KEY_MOUSEWHEELDOWN    },
106     { N_("Mouse Wheel Left"),  KEY_MOUSEWHEELLEFT    },
107     { N_("Mouse Wheel Right"), KEY_MOUSEWHEELRIGHT   },
108     { N_("Mouse Wheel Up"),    KEY_MOUSEWHEELUP      },
109     { N_("Page Down"),         KEY_PAGEDOWN          },
110     { N_("Page Up"),           KEY_PAGEUP            },
111     { N_("Pause"),             KEY_PAUSE             },
112     { N_("Print"),             KEY_PRINT             },
113     { N_("Right"),             KEY_RIGHT             },
114     { N_("Space"),             ' '                   },
115     { N_("Tab"),               KEY_TAB               },
116     { N_("Unset"),             KEY_UNSET             },
117     { N_("Up"),                KEY_UP                },
118     { N_("Volume Down"),       KEY_VOLUME_DOWN       },
119     { N_("Volume Mute"),       KEY_VOLUME_MUTE       },
120     { N_("Volume Up"),         KEY_VOLUME_UP         },
121     { N_("Zoom In"),           KEY_ZOOM_IN           },
122     { N_("Zoom Out"),          KEY_ZOOM_OUT          },
123 };
124 #define KEYS_COUNT (sizeof(vlc_keys)/sizeof(vlc_keys[0]))
125
126 static int keystrcmp (const void *key, const void *elem)
127 {
128     const char *sa = key, *sb = elem;
129     return strcmp (sa, sb);
130 }
131
132 /* Convert Unicode code point to UTF-8 */
133 static char *utf8_cp (uint_fast32_t cp, char *buf)
134 {
135     if (cp < (1 << 7))
136     {
137         buf[1] = 0;
138         buf[0] = cp;
139     }
140     else if (cp < (1 << 11))
141     {
142         buf[2] = 0;
143         buf[1] = 0x80 | (cp & 0x3F);
144         cp >>= 6;
145         buf[0] = 0xC0 | cp;
146     }
147     else if (cp < (1 << 16))
148     {
149         buf[3] = 0;
150         buf[2] = 0x80 | (cp & 0x3F);
151         cp >>= 6;
152         buf[1] = 0x80 | (cp & 0x3F);
153         cp >>= 6;
154         buf[0] = 0xE0 | cp;
155     }
156     else if (cp < (1 << 21))
157     {
158         buf[4] = 0;
159         buf[3] = 0x80 | (cp & 0x3F);
160         cp >>= 6;
161         buf[2] = 0x80 | (cp & 0x3F);
162         cp >>= 6;
163         buf[1] = 0x80 | (cp & 0x3F);
164         cp >>= 6;
165         buf[0] = 0xE0 | cp;
166     }
167     else
168         return NULL;
169     return buf;
170 }
171
172 /**
173  * Parse a human-readable string representation of a VLC key code.
174  * @note This only works with the American English representation
175  * (a.k.a. C or POSIX), not with the local representation returned from
176  * vlc_keycode2str().
177  * @return a VLC key code, or KEY_UNSET on failure.
178  */
179 uint_fast32_t vlc_str2keycode (const char *name)
180 {
181     uint_fast32_t mods = 0;
182     uint32_t code;
183
184     for (;;)
185     {
186         size_t len = strcspn (name, "-+");
187         if (len == 0 || name[len] == '\0')
188             break;
189
190         if (len == 4 && !strncasecmp (name, "Ctrl", 4))
191             mods |= KEY_MODIFIER_CTRL;
192         if (len == 3 && !strncasecmp (name, "Alt", 3))
193             mods |= KEY_MODIFIER_ALT;
194         if (len == 5 && !strncasecmp (name, "Shift", 5))
195             mods |= KEY_MODIFIER_SHIFT;
196         if (len == 4 && !strncasecmp (name, "Meta", 4))
197             mods |= KEY_MODIFIER_META;
198         if (len == 7 && !strncasecmp (name, "Command", 7))
199             mods |= KEY_MODIFIER_COMMAND;
200
201         name += len + 1;
202     }
203
204     key_descriptor_t *d = bsearch (name, vlc_keys, KEYS_COUNT,
205                                    sizeof (vlc_keys[0]), keystrcmp);
206     if (d != NULL)
207         code = d->i_key_code;
208     else
209     if (vlc_towc (name, &code) <= 0)
210         code = KEY_UNSET;
211
212     if (code != KEY_UNSET)
213         code |= mods;
214     return code;
215 }
216
217 static char *nooptext (const char *txt)
218 {
219     return (char *)txt;
220 }
221
222 /**
223  * Format a human-readable and unique representation of a VLC key code
224  * (including modifiers).
225  * @param code key code to translate to a string
226  * @param locale true to get a localized string,
227  *               false to get a C string suitable for 'vlcrc'
228  * @return a heap-allocated string, or NULL on error.
229  */
230 char *vlc_keycode2str (uint_fast32_t code, bool locale)
231 {
232     char *(*tr) (const char *) = locale ? vlc_gettext : nooptext;
233     const char *name;
234     char *str, buf[5];
235     uintptr_t key = code & ~KEY_MODIFIER;
236
237     for (size_t i = 0; i < KEYS_COUNT; i++)
238         if (vlc_keys[i].i_key_code == key)
239         {
240             name = vlc_keys[i].psz_key_string;
241             goto found;
242         }
243
244     if (utf8_cp (key, buf) == NULL)
245         return NULL;
246     name = buf;
247
248 found:
249     if (asprintf (&str, "%s%s%s%s%s%s",
250                   (code & KEY_MODIFIER_CTRL) ? tr(N_("Ctrl+")) : "",
251                   (code & KEY_MODIFIER_ALT) ? tr(N_("Alt+")) : "",
252                   (code & KEY_MODIFIER_SHIFT) ? tr(N_("Shift+")) : "",
253                   (code & KEY_MODIFIER_META) ? tr(N_("Meta+")) : "",
254                   (code & KEY_MODIFIER_COMMAND) ? tr(N_("Command+")) : "",
255                   tr(name)) == -1)
256         return NULL;
257     return str;
258 }
259
260
261 /*** VLC key map ***/
262
263 #define MAXACTION 20
264 struct action
265 {
266     char name[MAXACTION];
267     vlc_action_t value;
268 };
269
270 static const struct action actions[] =
271 {
272     /* *MUST* be sorted (ASCII order) */
273     { "aspect-ratio", ACTIONID_ASPECT_RATIO, },
274     { "audio-track", ACTIONID_AUDIO_TRACK, },
275     { "audiodelay-down", ACTIONID_AUDIODELAY_DOWN, },
276     { "audiodelay-up", ACTIONID_AUDIODELAY_UP, },
277     { "audiodevice-cycle", ACTIONID_AUDIODEVICE_CYCLE, },
278     { "chapter-next", ACTIONID_CHAPTER_NEXT, },
279     { "chapter-prev", ACTIONID_CHAPTER_PREV, },
280     { "clear-playlist", ACTIONID_PLAY_CLEAR, },
281     { "crop", ACTIONID_CROP, },
282     { "crop-bottom", ACTIONID_CROP_BOTTOM, },
283     { "crop-left", ACTIONID_CROP_LEFT, },
284     { "crop-right", ACTIONID_CROP_RIGHT, },
285     { "crop-top", ACTIONID_CROP_TOP, },
286     { "decr-scalefactor", ACTIONID_SCALE_DOWN, },
287     { "deinterlace", ACTIONID_DEINTERLACE, },
288     { "deinterlace-mode", ACTIONID_DEINTERLACE_MODE, },
289     { "disc-menu", ACTIONID_DISC_MENU, },
290     { "faster", ACTIONID_FASTER, },
291     { "frame-next", ACTIONID_FRAME_NEXT, },
292     { "incr-scalefactor", ACTIONID_SCALE_UP, },
293     { "intf-boss", ACTIONID_INTF_BOSS, },
294     { "intf-popup-menu", ACTIONID_INTF_POPUP_MENU, },
295     { "intf-show", ACTIONID_INTF_TOGGLE_FSC, },
296     { "jump+extrashort", ACTIONID_JUMP_FORWARD_EXTRASHORT, },
297     { "jump+long", ACTIONID_JUMP_FORWARD_LONG, },
298     { "jump+medium", ACTIONID_JUMP_FORWARD_MEDIUM, },
299     { "jump+short", ACTIONID_JUMP_FORWARD_SHORT, },
300     { "jump-extrashort", ACTIONID_JUMP_BACKWARD_EXTRASHORT, },
301     { "jump-long", ACTIONID_JUMP_BACKWARD_LONG, },
302     { "jump-medium", ACTIONID_JUMP_BACKWARD_MEDIUM, },
303     { "jump-short", ACTIONID_JUMP_BACKWARD_SHORT, },
304     { "leave-fullscreen", ACTIONID_LEAVE_FULLSCREEN, },
305     { "loop", ACTIONID_LOOP, },
306     { "nav-activate", ACTIONID_NAV_ACTIVATE, },
307     { "nav-down", ACTIONID_NAV_DOWN, },
308     { "nav-left", ACTIONID_NAV_LEFT, },
309     { "nav-right", ACTIONID_NAV_RIGHT, },
310     { "nav-up", ACTIONID_NAV_UP, },
311     { "next", ACTIONID_NEXT, },
312     { "pause", ACTIONID_PAUSE, },
313     { "play", ACTIONID_PLAY, },
314     { "play-bookmark1", ACTIONID_PLAY_BOOKMARK1, },
315     { "play-bookmark10", ACTIONID_PLAY_BOOKMARK10, },
316     { "play-bookmark2", ACTIONID_PLAY_BOOKMARK2, },
317     { "play-bookmark3", ACTIONID_PLAY_BOOKMARK3, },
318     { "play-bookmark4", ACTIONID_PLAY_BOOKMARK4, },
319     { "play-bookmark5", ACTIONID_PLAY_BOOKMARK5, },
320     { "play-bookmark6", ACTIONID_PLAY_BOOKMARK6, },
321     { "play-bookmark7", ACTIONID_PLAY_BOOKMARK7, },
322     { "play-bookmark8", ACTIONID_PLAY_BOOKMARK8, },
323     { "play-bookmark9", ACTIONID_PLAY_BOOKMARK9, },
324     { "play-pause", ACTIONID_PLAY_PAUSE, },
325     { "position", ACTIONID_POSITION, },
326     { "prev", ACTIONID_PREV, },
327     { "program-sid-next", ACTIONID_PROGRAM_SID_NEXT, },
328     { "program-sid-prev", ACTIONID_PROGRAM_SID_PREV, },
329     { "quit", ACTIONID_QUIT, },
330     { "random", ACTIONID_RANDOM, },
331     { "rate-faster-fine", ACTIONID_RATE_FASTER_FINE, },
332     { "rate-normal", ACTIONID_RATE_NORMAL, },
333     { "rate-slower-fine", ACTIONID_RATE_SLOWER_FINE, },
334     { "record", ACTIONID_RECORD, },
335     { "set-bookmark1", ACTIONID_SET_BOOKMARK1, },
336     { "set-bookmark10", ACTIONID_SET_BOOKMARK10, },
337     { "set-bookmark2", ACTIONID_SET_BOOKMARK2, },
338     { "set-bookmark3", ACTIONID_SET_BOOKMARK3, },
339     { "set-bookmark4", ACTIONID_SET_BOOKMARK4, },
340     { "set-bookmark5", ACTIONID_SET_BOOKMARK5, },
341     { "set-bookmark6", ACTIONID_SET_BOOKMARK6, },
342     { "set-bookmark7", ACTIONID_SET_BOOKMARK7, },
343     { "set-bookmark8", ACTIONID_SET_BOOKMARK8, },
344     { "set-bookmark9", ACTIONID_SET_BOOKMARK9, },
345     { "slower", ACTIONID_SLOWER, },
346     { "snapshot", ACTIONID_SNAPSHOT, },
347     { "stop", ACTIONID_STOP, },
348     { "subdelay-down", ACTIONID_SUBDELAY_DOWN, },
349     { "subdelay-up", ACTIONID_SUBDELAY_UP, },
350     { "subpos-down", ACTIONID_SUBPOS_DOWN, },
351     { "subpos-up", ACTIONID_SUBPOS_UP, },
352     { "subsync-apply", ACTIONID_SUBSYNC_APPLY, },
353     { "subsync-markaudio", ACTIONID_SUBSYNC_MARKAUDIO, },
354     { "subsync-marksub", ACTIONID_SUBSYNC_MARKSUB, },
355     { "subsync-reset", ACTIONID_SUBSYNC_RESET, },
356     { "subtitle-toggle", ACTIONID_SUBTITLE_TOGGLE, },
357     { "subtitle-track", ACTIONID_SUBTITLE_TRACK, },
358     { "title-next", ACTIONID_TITLE_NEXT, },
359     { "title-prev", ACTIONID_TITLE_PREV, },
360     { "toggle-autoscale", ACTIONID_TOGGLE_AUTOSCALE, },
361     { "toggle-fullscreen", ACTIONID_TOGGLE_FULLSCREEN, },
362     { "uncrop-bottom", ACTIONID_UNCROP_BOTTOM, },
363     { "uncrop-left", ACTIONID_UNCROP_LEFT, },
364     { "uncrop-right", ACTIONID_UNCROP_RIGHT, },
365     { "uncrop-top", ACTIONID_UNCROP_TOP, },
366     { "unzoom", ACTIONID_UNZOOM, },
367     { "vol-down", ACTIONID_VOL_DOWN, },
368     { "vol-mute", ACTIONID_VOL_MUTE, },
369     { "vol-up", ACTIONID_VOL_UP, },
370     { "wallpaper", ACTIONID_WALLPAPER, },
371     { "zoom", ACTIONID_ZOOM, },
372     { "zoom-double", ACTIONID_ZOOM_DOUBLE, },
373     { "zoom-half", ACTIONID_ZOOM_HALF, },
374     { "zoom-original", ACTIONID_ZOOM_ORIGINAL, },
375     { "zoom-quarter", ACTIONID_ZOOM_QUARTER, },
376 };
377 #define ACTIONS_COUNT (sizeof (actions) / sizeof (actions[0]))
378
379 struct mapping
380 {
381     uint32_t     key; ///< Key code
382     vlc_action_t action; ///< Action ID
383 };
384
385 static int keycmp (const void *a, const void *b)
386 {
387     const struct mapping *ka = a, *kb = b;
388
389     return (ka->key < kb->key) ? -1 : (ka->key > kb->key) ? +1 : 0;
390 }
391
392 struct vlc_actions
393 {
394     void *map; /* Key map */
395     void *global_map; /* Grabbed/global key map */
396     struct hotkey keys[1];
397 };
398
399 static int vlc_key_to_action (vlc_object_t *obj, const char *varname,
400                               vlc_value_t prevkey, vlc_value_t curkey, void *d)
401 {
402     void *const *map = d;
403     const struct mapping **pent;
404     uint32_t keycode = curkey.i_int;
405
406     pent = tfind (&keycode, map, keycmp);
407     if (pent == NULL)
408         return VLC_SUCCESS;
409
410     (void) varname;
411     (void) prevkey;
412     return var_SetInteger (obj, "key-action", (*pent)->action);
413 }
414
415 /**
416  * Adds a mapping from a certain key code to a certain action.
417  */
418 static int vlc_AddMapping (void **map, uint32_t keycode, vlc_action_t action)
419 {
420     struct mapping *entry = malloc (sizeof (*entry));
421     if (entry == NULL)
422         return ENOMEM;
423     entry->key = keycode;
424     entry->action = action;
425
426     struct mapping **pent = tsearch (entry, map, keycmp);
427     if (unlikely(pent == NULL))
428         return ENOMEM;
429     if (*pent != entry)
430     {
431         free (entry);
432         return EEXIST;
433     }
434     return 0;
435 }
436
437 static void vlc_AddWheelMapping (void **map, uint32_t kmore, uint32_t kless,
438                                  int mode)
439 {
440     vlc_action_t amore = ACTIONID_NONE, aless = ACTIONID_NONE;
441
442     switch (mode)
443     {
444         case 0: /* volume up/down */
445             amore = ACTIONID_VOL_UP;
446             aless = ACTIONID_VOL_DOWN;
447             break;
448         case 2: /* position latter/earlier */
449             amore = ACTIONID_JUMP_FORWARD_EXTRASHORT;
450             aless = ACTIONID_JUMP_BACKWARD_EXTRASHORT;
451             break;
452         case 3: /* position earlier/latter */
453             amore = ACTIONID_JUMP_BACKWARD_EXTRASHORT;
454             aless = ACTIONID_JUMP_FORWARD_EXTRASHORT;
455             break;
456     }
457
458     if (amore != ACTIONID_NONE)
459         vlc_AddMapping (map, kmore, amore);
460     if (aless != ACTIONID_NONE)
461         vlc_AddMapping (map, kless, aless);
462 }
463
464
465 /**
466  * Sets up all key mappings for a given action.
467  * \param map tree (of struct mapping entries) to write mappings to
468  * \param confname VLC configuration item to read mappings from
469  * \param action action ID
470  */
471 static void vlc_InitAction (vlc_object_t *obj, void **map,
472                             const char *confname, vlc_action_t action)
473 {
474     char *keys = var_InheritString (obj, confname);
475     if (keys == NULL)
476         return;
477
478     for (char *buf, *key = strtok_r (keys, "\t", &buf);
479          key != NULL;
480          key = strtok_r (NULL, "\t", &buf))
481     {
482         uint32_t code = vlc_str2keycode (key);
483         if (code == KEY_UNSET)
484         {
485             msg_Warn (obj, "Key \"%s\" unrecognized", key);
486             continue;
487         }
488
489         if (vlc_AddMapping (map, code, action) == EEXIST)
490             msg_Warn (obj, "Key \"%s\" bound to multiple actions", key);
491     }
492     free (keys);
493 }
494
495 /**
496  * Initializes the key map from configuration.
497  */
498 struct vlc_actions *vlc_InitActions (libvlc_int_t *libvlc)
499 {
500     vlc_object_t *obj = VLC_OBJECT(libvlc);
501     struct hotkey *keys;
502     struct vlc_actions *as = malloc (sizeof (*as) + ACTIONS_COUNT * sizeof (*keys));
503
504     if (unlikely(as == NULL))
505         return NULL;
506     as->map = NULL;
507     as->global_map = NULL;
508     keys = as->keys;
509
510     var_Create (obj, "key-pressed", VLC_VAR_INTEGER);
511     var_Create (obj, "global-key-pressed", VLC_VAR_INTEGER);
512     var_Create (obj, "key-action", VLC_VAR_INTEGER);
513
514     /* Initialize from configuration */
515     for (size_t i = 0; i < ACTIONS_COUNT; i++)
516     {
517 #ifndef NDEBUG
518         if (i > 0
519          && strcmp (actions[i-1].name, actions[i].name) >= 0)
520         {
521             msg_Err (libvlc, "key-%s and key-%s are not ordered properly",
522                      actions[i-1].name, actions[i].name);
523             abort ();
524         }
525 #endif
526         keys->psz_action = actions[i].name;
527         keys++;
528
529         char name[12 + MAXACTION];
530
531         snprintf (name, sizeof (name), "global-key-%s", actions[i].name);
532         vlc_InitAction (obj, &as->map, name + 7, actions[i].value);
533         vlc_InitAction (obj, &as->global_map, name, actions[i].value);
534     }
535     keys->psz_action = NULL;
536
537     /* Initialize mouse wheel events */
538     vlc_AddWheelMapping (&as->map, KEY_MOUSEWHEELRIGHT, KEY_MOUSEWHEELLEFT,
539                          var_InheritInteger (obj, "hotkeys-x-wheel-mode"));
540     vlc_AddWheelMapping (&as->map, KEY_MOUSEWHEELUP, KEY_MOUSEWHEELDOWN,
541                          var_InheritInteger (obj, "hotkeys-y-wheel-mode"));
542
543     libvlc->p_hotkeys = as->keys;
544     var_AddCallback (obj, "key-pressed", vlc_key_to_action, &as->map);
545     var_AddCallback (obj, "global-key-pressed", vlc_key_to_action,
546                      &as->global_map);
547     return as;
548 }
549
550 /**
551  * Destroys the key map.
552  */
553 void vlc_DeinitActions (libvlc_int_t *libvlc, struct vlc_actions *as)
554 {
555     if (unlikely(as == NULL))
556         return;
557
558     var_DelCallback (libvlc, "global-key-pressed", vlc_key_to_action,
559                      &as->global_map);
560     var_DelCallback (libvlc, "key-pressed", vlc_key_to_action, &as->map);
561
562     tdestroy (as->global_map, free);
563     tdestroy (as->map, free);
564     free (as);
565     libvlc->p_hotkeys = NULL;
566 }
567
568
569 static int actcmp(const void *key, const void *ent)
570 {
571     const struct action *act = ent;
572     return strcmp(key, act->name);
573 }
574
575 /**
576  * Get the action ID from the action name in the configuration subsystem.
577  * @return the action ID or ACTIONID_NONE on error.
578  */
579 vlc_action_t vlc_GetActionId (const char *name)
580 {
581     const struct action *act;
582
583     if (strncmp (name, "key-", 4))
584         return ACTIONID_NONE;
585     name += 4;
586
587     act = bsearch(name, actions, ACTIONS_COUNT, sizeof(*act), actcmp);
588     return (act != NULL) ? act->value : ACTIONID_NONE;
589 }