Change the "intf-show" variable into a toggle.
[vlc.git] / src / config / keys.c
blobb07215ccbe65c36a584bf2832d64a87ca8416598
1 /*****************************************************************************
2 * keys.c: keys configuration
3 *****************************************************************************
4 * Copyright (C) 2003-2009 the VideoLAN team
6 * Authors: Sigmund Augdal Helberg <dnumgis@videolan.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 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 General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
27 /**
28 * \file
29 * This file defines functions and structures for hotkey handling in vlc
32 #ifdef HAVE_CONFIG_H
33 # include <config.h>
34 #endif
36 #include <stdlib.h>
37 #include <limits.h>
38 #ifdef HAVE_SEARCH_H
39 # include <search.h>
40 #endif
42 #include <vlc_common.h>
43 #include <vlc_keys.h>
44 #include "configuration.h"
45 #include "libvlc.h"
47 typedef struct key_descriptor_s
49 const char psz_key_string[20];
50 uint32_t i_key_code;
51 } key_descriptor_t;
53 static const struct key_descriptor_s vlc_keys[] =
54 { /* Alphabetical order */
55 { "Backspace", KEY_BACKSPACE },
56 { "Browser Back", KEY_BROWSER_BACK },
57 { "Browser Favorites", KEY_BROWSER_FAVORITES },
58 { "Browser Forward", KEY_BROWSER_FORWARD },
59 { "Browser Home", KEY_BROWSER_HOME },
60 { "Browser Refresh", KEY_BROWSER_REFRESH },
61 { "Browser Search", KEY_BROWSER_SEARCH },
62 { "Browser Stop", KEY_BROWSER_STOP },
63 { "Delete", KEY_DELETE },
64 { "Down", KEY_DOWN },
65 { "End", KEY_END },
66 { "Enter", KEY_ENTER },
67 { "Esc", KEY_ESC },
68 { "F1", KEY_F1 },
69 { "F10", KEY_F10 },
70 { "F11", KEY_F11 },
71 { "F12", KEY_F12 },
72 { "F2", KEY_F2 },
73 { "F3", KEY_F3 },
74 { "F4", KEY_F4 },
75 { "F5", KEY_F5 },
76 { "F6", KEY_F6 },
77 { "F7", KEY_F7 },
78 { "F8", KEY_F8 },
79 { "F9", KEY_F9 },
80 { "Home", KEY_HOME },
81 { "Insert", KEY_INSERT },
82 { "Left", KEY_LEFT },
83 { "Media Next Track", KEY_MEDIA_NEXT_TRACK },
84 { "Media Play Pause", KEY_MEDIA_PLAY_PAUSE },
85 { "Media Prev Track", KEY_MEDIA_PREV_TRACK },
86 { "Media Stop", KEY_MEDIA_STOP },
87 { "Menu", KEY_MENU },
88 { "Mouse Wheel Down", KEY_MOUSEWHEELDOWN },
89 { "Mouse Wheel Left", KEY_MOUSEWHEELLEFT },
90 { "Mouse Wheel Right", KEY_MOUSEWHEELRIGHT },
91 { "Mouse Wheel Up", KEY_MOUSEWHEELUP },
92 { "Page Down", KEY_PAGEDOWN },
93 { "Page Up", KEY_PAGEUP },
94 { "Right", KEY_RIGHT },
95 { "Space", ' ' },
96 { "Tab", KEY_TAB },
97 { "Unset", KEY_UNSET },
98 { "Up", KEY_UP },
99 { "Volume Mute", KEY_VOLUME_MUTE },
100 { "Volume Down", KEY_VOLUME_DOWN },
101 { "Volume Up", KEY_VOLUME_UP },
103 #define KEYS_COUNT (sizeof(vlc_keys)/sizeof(vlc_keys[0]))
105 static int keystrcmp (const void *key, const void *elem)
107 const char *sa = key, *sb = elem;
108 return strcmp (sa, sb);
111 /* Convert Unicode code point to UTF-8 */
112 static char *utf8_cp (uint_fast32_t cp, char *buf)
114 if (cp < (1 << 7))
116 buf[1] = 0;
117 buf[0] = cp;
119 else if (cp < (1 << 11))
121 buf[2] = 0;
122 buf[1] = 0x80 | (cp & 0x3F);
123 cp >>= 6;
124 buf[0] = 0xC0 | cp;
126 else if (cp < (1 << 16))
128 buf[3] = 0;
129 buf[2] = 0x80 | (cp & 0x3F);
130 cp >>= 6;
131 buf[1] = 0x80 | (cp & 0x3F);
132 cp >>= 6;
133 buf[0] = 0xE0 | cp;
135 else if (cp < (1 << 21))
137 buf[4] = 0;
138 buf[3] = 0x80 | (cp & 0x3F);
139 cp >>= 6;
140 buf[2] = 0x80 | (cp & 0x3F);
141 cp >>= 6;
142 buf[1] = 0x80 | (cp & 0x3F);
143 cp >>= 6;
144 buf[0] = 0xE0 | cp;
146 else
147 return NULL;
148 return buf;
152 * Parse a human-readable string representation of a VLC key code.
153 * @return a VLC key code, or KEY_UNSET on failure.
155 uint_fast32_t vlc_str2keycode (const char *name)
157 uint_fast32_t mods = 0;
158 uint32_t code;
160 for (;;)
162 size_t len = strcspn (name, "-+");
163 if (len == 0 || name[len] == '\0')
164 break;
166 if (len == 4 && !strncasecmp (name, "Ctrl", 4))
167 mods |= KEY_MODIFIER_CTRL;
168 if (len == 3 && !strncasecmp (name, "Alt", 3))
169 mods |= KEY_MODIFIER_ALT;
170 if (len == 5 && !strncasecmp (name, "Shift", 5))
171 mods |= KEY_MODIFIER_SHIFT;
172 if (len == 4 && !strncasecmp (name, "Meta", 4))
173 mods |= KEY_MODIFIER_META;
174 if (len == 7 && !strncasecmp (name, "Command", 7))
175 mods |= KEY_MODIFIER_COMMAND;
177 name += len + 1;
180 key_descriptor_t *d = bsearch (name, vlc_keys, KEYS_COUNT,
181 sizeof (vlc_keys[0]), keystrcmp);
182 if (d != NULL)
183 code = d->i_key_code;
184 else
185 if (vlc_towc (name, &code) <= 0)
186 code = KEY_UNSET;
188 if (code != KEY_UNSET)
189 code |= mods;
190 return code;
194 * Format a human-readable and unique representation of a VLC key code
195 * (including modifiers).
196 * @return a heap-allocated string, or NULL on error.
198 char *vlc_keycode2str (uint_fast32_t code)
200 const char *name;
201 char *str, buf[5];
202 uintptr_t key = code & ~KEY_MODIFIER;
204 for (size_t i = 0; i < KEYS_COUNT; i++)
205 if (vlc_keys[i].i_key_code == key)
207 name = vlc_keys[i].psz_key_string;
208 goto found;
211 if (utf8_cp (key, buf) == NULL)
212 return NULL;
213 name = buf;
215 found:
216 if (asprintf (&str, "%s%s%s%s%s%s",
217 (code & KEY_MODIFIER_CTRL) ? "Ctrl+" : "",
218 (code & KEY_MODIFIER_ALT) ? "Alt+" : "",
219 (code & KEY_MODIFIER_SHIFT) ? "Shift+" : "",
220 (code & KEY_MODIFIER_META) ? "Meta+" : "",
221 (code & KEY_MODIFIER_COMMAND) ? "Command+" : "", name) == -1)
222 return NULL;
223 return str;
227 /*** VLC key map ***/
229 #define MAXACTION 20
230 struct action
232 char name[MAXACTION];
233 vlc_action_t value;
236 static const struct action actions[] =
238 /* *MUST* be sorted (ASCII order) */
239 { "aspect-ratio", ACTIONID_ASPECT_RATIO, },
240 { "audio-track", ACTIONID_AUDIO_TRACK, },
241 { "audiodelay-down", ACTIONID_AUDIODELAY_DOWN, },
242 { "audiodelay-up", ACTIONID_AUDIODELAY_UP, },
243 { "audiodevice-cycle", ACTIONID_AUDIODEVICE_CYCLE, },
244 { "chapter-next", ACTIONID_CHAPTER_NEXT, },
245 { "chapter-prev", ACTIONID_CHAPTER_PREV, },
246 { "crop", ACTIONID_CROP, },
247 { "crop-bottom", ACTIONID_CROP_BOTTOM, },
248 { "crop-left", ACTIONID_CROP_LEFT, },
249 { "crop-right", ACTIONID_CROP_RIGHT, },
250 { "crop-top", ACTIONID_CROP_TOP, },
251 { "decr-scalefactor", ACTIONID_SCALE_DOWN, },
252 { "deinterlace", ACTIONID_DEINTERLACE, },
253 { "disc-menu", ACTIONID_DISC_MENU, },
254 { "faster", ACTIONID_FASTER, },
255 { "frame-next", ACTIONID_FRAME_NEXT, },
256 { "incr-scalefactor", ACTIONID_SCALE_UP, },
257 { "intf-boss", ACTIONID_INTF_BOSS, },
258 { "intf-show", ACTIONID_INTF_TOGGLE_FSC, },
259 { "jump+extrashort", ACTIONID_JUMP_FORWARD_EXTRASHORT, },
260 { "jump+long", ACTIONID_JUMP_FORWARD_LONG, },
261 { "jump+medium", ACTIONID_JUMP_FORWARD_MEDIUM, },
262 { "jump+short", ACTIONID_JUMP_FORWARD_SHORT, },
263 { "jump-extrashort", ACTIONID_JUMP_BACKWARD_EXTRASHORT, },
264 { "jump-long", ACTIONID_JUMP_BACKWARD_LONG, },
265 { "jump-medium", ACTIONID_JUMP_BACKWARD_MEDIUM, },
266 { "jump-short", ACTIONID_JUMP_BACKWARD_SHORT, },
267 { "leave-fullscreen", ACTIONID_LEAVE_FULLSCREEN, },
268 { "loop", ACTIONID_LOOP, },
269 { "menu-down", ACTIONID_MENU_DOWN, },
270 { "menu-left", ACTIONID_MENU_LEFT, },
271 { "menu-off", ACTIONID_MENU_OFF, },
272 { "menu-on", ACTIONID_MENU_ON, },
273 { "menu-right", ACTIONID_MENU_RIGHT, },
274 { "menu-select", ACTIONID_MENU_SELECT, },
275 { "menu-up", ACTIONID_MENU_UP, },
276 { "nav-activate", ACTIONID_NAV_ACTIVATE, },
277 { "nav-down", ACTIONID_NAV_DOWN, },
278 { "nav-left", ACTIONID_NAV_LEFT, },
279 { "nav-right", ACTIONID_NAV_RIGHT, },
280 { "nav-up", ACTIONID_NAV_UP, },
281 { "next", ACTIONID_NEXT, },
282 { "pause", ACTIONID_PAUSE, },
283 { "play", ACTIONID_PLAY, },
284 { "play-bookmark1", ACTIONID_PLAY_BOOKMARK1, },
285 { "play-bookmark10", ACTIONID_PLAY_BOOKMARK10, },
286 { "play-bookmark2", ACTIONID_PLAY_BOOKMARK2, },
287 { "play-bookmark3", ACTIONID_PLAY_BOOKMARK3, },
288 { "play-bookmark4", ACTIONID_PLAY_BOOKMARK4, },
289 { "play-bookmark5", ACTIONID_PLAY_BOOKMARK5, },
290 { "play-bookmark6", ACTIONID_PLAY_BOOKMARK6, },
291 { "play-bookmark7", ACTIONID_PLAY_BOOKMARK7, },
292 { "play-bookmark8", ACTIONID_PLAY_BOOKMARK8, },
293 { "play-bookmark9", ACTIONID_PLAY_BOOKMARK9, },
294 { "play-pause", ACTIONID_PLAY_PAUSE, },
295 { "position", ACTIONID_POSITION, },
296 { "prev", ACTIONID_PREV, },
297 { "quit", ACTIONID_QUIT, },
298 { "random", ACTIONID_RANDOM, },
299 { "rate-faster-fine", ACTIONID_RATE_FASTER_FINE, },
300 { "rate-normal", ACTIONID_RATE_NORMAL, },
301 { "rate-slower-fine", ACTIONID_RATE_SLOWER_FINE, },
302 { "record", ACTIONID_RECORD, },
303 { "set-bookmark1", ACTIONID_SET_BOOKMARK1, },
304 { "set-bookmark10", ACTIONID_SET_BOOKMARK10, },
305 { "set-bookmark2", ACTIONID_SET_BOOKMARK2, },
306 { "set-bookmark3", ACTIONID_SET_BOOKMARK3, },
307 { "set-bookmark4", ACTIONID_SET_BOOKMARK4, },
308 { "set-bookmark5", ACTIONID_SET_BOOKMARK5, },
309 { "set-bookmark6", ACTIONID_SET_BOOKMARK6, },
310 { "set-bookmark7", ACTIONID_SET_BOOKMARK7, },
311 { "set-bookmark8", ACTIONID_SET_BOOKMARK8, },
312 { "set-bookmark9", ACTIONID_SET_BOOKMARK9, },
313 { "slower", ACTIONID_SLOWER, },
314 { "snapshot", ACTIONID_SNAPSHOT, },
315 { "stop", ACTIONID_STOP, },
316 { "subdelay-down", ACTIONID_SUBDELAY_DOWN, },
317 { "subdelay-up", ACTIONID_SUBDELAY_UP, },
318 { "subpos-down", ACTIONID_SUBPOS_DOWN, },
319 { "subpos-up", ACTIONID_SUBPOS_UP, },
320 { "subtitle-track", ACTIONID_SUBTITLE_TRACK, },
321 { "title-next", ACTIONID_TITLE_NEXT, },
322 { "title-prev", ACTIONID_TITLE_PREV, },
323 { "toggle-autoscale", ACTIONID_TOGGLE_AUTOSCALE, },
324 { "toggle-fullscreen", ACTIONID_TOGGLE_FULLSCREEN, },
325 { "uncrop-bottom", ACTIONID_UNCROP_BOTTOM, },
326 { "uncrop-left", ACTIONID_UNCROP_LEFT, },
327 { "uncrop-right", ACTIONID_UNCROP_RIGHT, },
328 { "uncrop-top", ACTIONID_UNCROP_TOP, },
329 { "unzoom", ACTIONID_UNZOOM, },
330 { "vol-down", ACTIONID_VOL_DOWN, },
331 { "vol-mute", ACTIONID_VOL_MUTE, },
332 { "vol-up", ACTIONID_VOL_UP, },
333 { "wallpaper", ACTIONID_WALLPAPER, },
334 { "zoom", ACTIONID_ZOOM, },
335 { "zoom-double", ACTIONID_ZOOM_DOUBLE, },
336 { "zoom-half", ACTIONID_ZOOM_HALF, },
337 { "zoom-original", ACTIONID_ZOOM_ORIGINAL, },
338 { "zoom-quarter", ACTIONID_ZOOM_QUARTER, },
340 #define ACTIONS_COUNT (sizeof (actions) / sizeof (actions[0]))
342 struct mapping
344 uint32_t key; ///< Key code
345 vlc_action_t action; ///< Action ID
348 static int keycmp (const void *a, const void *b)
350 const struct mapping *ka = a, *kb = b;
352 #if (INT_MAX >= 0x7fffffff)
353 return ka->key - kb->key;
354 #else
355 return (ka->key < kb->key) ? -1 : (ka->key > kb->key) ? +1 : 0;
356 #endif
359 struct vlc_actions
361 void *map; /* Key map */
362 void *global_map; /* Grabbed/global key map */
363 struct hotkey keys[0];
366 static int vlc_key_to_action (vlc_object_t *obj, const char *varname,
367 vlc_value_t prevkey, vlc_value_t curkey, void *d)
369 void *const *map = d;
370 const struct mapping **pent;
371 uint32_t keycode = curkey.i_int;
373 pent = tfind (&keycode, map, keycmp);
374 if (pent == NULL)
375 return VLC_SUCCESS;
377 (void) varname;
378 (void) prevkey;
379 return var_SetInteger (obj, "key-action", (*pent)->action);
383 * Sets up all key mappings for a given action.
384 * \param map tree (of struct mapping entries) to write mappings to
385 * \param confname VLC configuration item to read mappings from
386 * \param action action ID
388 static void vlc_MapAction (vlc_object_t *obj, void **map,
389 const char *confname, vlc_action_t action)
391 char *keys = var_InheritString (obj, confname);
392 if (keys == NULL)
393 return;
395 for (char *buf, *key = strtok_r (keys, "\t", &buf);
396 key != NULL;
397 key = strtok_r (NULL, "\t", &buf))
399 uint32_t code = vlc_str2keycode (key);
400 if (code == KEY_UNSET)
402 msg_Warn (obj, "Key \"%s\" unrecognized", key);
403 continue;
406 struct mapping *entry = malloc (sizeof (*entry));
407 if (entry == NULL)
408 continue;
409 entry->key = code;
410 entry->action = action;
412 struct mapping **pent = tsearch (entry, map, keycmp);
413 if (unlikely(pent == NULL))
414 continue;
415 if (*pent != entry)
417 free (entry);
418 msg_Warn (obj, "Key \"%s\" bound to multiple actions", key);
421 free (keys);
426 * Initializes the key map from configuration.
428 struct vlc_actions *vlc_InitActions (libvlc_int_t *libvlc)
430 vlc_object_t *obj = VLC_OBJECT(libvlc);
431 struct hotkey *keys;
432 struct vlc_actions *as = malloc (sizeof (*as) + (ACTIONS_COUNT + 1) * sizeof (*keys));
434 if (unlikely(as == NULL))
435 return NULL;
436 as->map = NULL;
437 as->global_map = NULL;
438 keys = as->keys;
440 var_Create (obj, "key-pressed", VLC_VAR_INTEGER);
441 var_Create (obj, "global-key-pressed", VLC_VAR_INTEGER);
442 var_Create (obj, "key-action", VLC_VAR_INTEGER);
444 /* Initialize from configuration */
445 for (size_t i = 0; i < ACTIONS_COUNT; i++)
447 #ifndef NDEBUG
448 if (i > 0
449 && strcmp (actions[i-1].name, actions[i].name) >= 0)
451 msg_Err (libvlc, "key-%s and key-%s are not ordered properly",
452 actions[i-1].name, actions[i].name);
453 abort ();
455 #endif
456 keys->psz_action = actions[i].name;
457 keys++;
459 char name[12 + MAXACTION];
461 snprintf (name, sizeof (name), "global-key-%s", actions[i].name);
462 vlc_MapAction (obj, &as->map, name + 7, actions[i].value);
463 vlc_MapAction (obj, &as->global_map, name, actions[i].value);
466 keys->psz_action = NULL;
468 libvlc->p_hotkeys = as->keys;
469 var_AddCallback (obj, "key-pressed", vlc_key_to_action, &as->map);
470 var_AddCallback (obj, "global-key-pressed", vlc_key_to_action,
471 &as->global_map);
472 return as;
476 * Destroys the key map.
478 void vlc_DeinitActions (libvlc_int_t *libvlc, struct vlc_actions *as)
480 if (unlikely(as == NULL))
481 return;
483 var_DelCallback (libvlc, "global-key-pressed", vlc_key_to_action,
484 &as->global_map);
485 var_DelCallback (libvlc, "key-pressed", vlc_key_to_action, &as->map);
487 tdestroy (as->global_map, free);
488 tdestroy (as->map, free);
489 free (as);
490 libvlc->p_hotkeys = NULL;
494 static int actcmp(const void *key, const void *ent)
496 const struct action *act = ent;
497 return strcmp(key, act->name);
501 * Get the action ID from the action name in the configuration subsystem.
502 * @return the action ID or ACTIONID_NONE on error.
504 vlc_action_t vlc_GetActionId (const char *name)
506 const struct action *act;
508 if (strncmp (name, "key-", 4))
509 return ACTIONID_NONE;
510 name += 4;
512 act = bsearch(name, actions, ACTIONS_COUNT, sizeof(*act), actcmp);
513 return (act != NULL) ? act->value : ACTIONID_NONE;