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 *****************************************************************************/
29 * This file defines functions and structures for hotkey handling in vlc
39 #include <vlc_common.h>
41 #include "configuration.h"
44 typedef struct key_descriptor_s
46 const char psz_key_string[20];
50 static const struct key_descriptor_s vlc_keys[] =
52 { "Unset", KEY_UNSET },
53 { "Backspace", KEY_BACKSPACE },
55 { "Enter", KEY_ENTER },
59 { "Right", KEY_RIGHT },
76 { "Insert", KEY_INSERT },
77 { "Delete", KEY_DELETE },
79 { "Page Up", KEY_PAGEUP },
80 { "Page Down", KEY_PAGEDOWN },
81 { "Browser Back", KEY_BROWSER_BACK },
82 { "Browser Forward", KEY_BROWSER_FORWARD },
83 { "Browser Refresh", KEY_BROWSER_REFRESH },
84 { "Browser Stop", KEY_BROWSER_STOP },
85 { "Browser Search", KEY_BROWSER_SEARCH },
86 { "Browser Favorites", KEY_BROWSER_FAVORITES },
87 { "Browser Home", KEY_BROWSER_HOME },
88 { "Volume Mute", KEY_VOLUME_MUTE },
89 { "Volume Down", KEY_VOLUME_DOWN },
90 { "Volume Up", KEY_VOLUME_UP },
91 { "Media Next Track", KEY_MEDIA_NEXT_TRACK },
92 { "Media Prev Track", KEY_MEDIA_PREV_TRACK },
93 { "Media Stop", KEY_MEDIA_STOP },
94 { "Media Play Pause", KEY_MEDIA_PLAY_PAUSE },
95 { "Mouse Wheel Up", KEY_MOUSEWHEELUP },
96 { "Mouse Wheel Down", KEY_MOUSEWHEELDOWN },
97 { "Mouse Wheel Left", KEY_MOUSEWHEELLEFT },
98 { "Mouse Wheel Right", KEY_MOUSEWHEELRIGHT },
100 enum { vlc_num_keys=sizeof(vlc_keys)/sizeof(struct key_descriptor_s) };
102 static int cmpkey (const void *key, const void *elem)
104 return ((uintptr_t)key) - ((key_descriptor_t *)elem)->i_key_code;
107 /* Convert Unicode code point to UTF-8 */
108 static char *utf8_cp (uint_fast32_t cp, char *buf)
115 else if (cp < (1 << 11))
118 buf[1] = 0x80 | (cp & 0x3F);
122 else if (cp < (1 << 16))
125 buf[2] = 0x80 | (cp & 0x3F);
127 buf[1] = 0x80 | (cp & 0x3F);
131 else if (cp < (1 << 21))
134 buf[3] = 0x80 | (cp & 0x3F);
136 buf[2] = 0x80 | (cp & 0x3F);
138 buf[1] = 0x80 | (cp & 0x3F);
147 uint_fast32_t ConfigStringToKey (const char *name)
149 uint_fast32_t mods = 0;
154 size_t len = strcspn (name, "-+");
155 if (len == 0 || name[len] == '\0')
158 if (len == 4 && !strncasecmp (name, "Ctrl", 4))
159 mods |= KEY_MODIFIER_CTRL;
160 if (len == 3 && !strncasecmp (name, "Alt", 3))
161 mods |= KEY_MODIFIER_ALT;
162 if (len == 5 && !strncasecmp (name, "Shift", 5))
163 mods |= KEY_MODIFIER_SHIFT;
164 if (len == 4 && !strncasecmp (name, "Meta", 4))
165 mods |= KEY_MODIFIER_META;
166 if (len == 7 && !strncasecmp (name, "Command", 7))
167 mods |= KEY_MODIFIER_COMMAND;
172 for (size_t i = 0; i < vlc_num_keys; i++)
173 if (!strcasecmp( vlc_keys[i].psz_key_string, name))
174 return vlc_keys[i].i_key_code | mods;
176 return (vlc_towc (name, &cp) > 0) ? (mods | cp) : KEY_UNSET;
180 * Format a human-readable and unique representation of a VLC key code
181 * (including modifiers).
182 * @return a heap-allocated string, or NULL on error.
184 char *vlc_keycode2str (uint_fast32_t code)
187 uintptr_t key = code & ~KEY_MODIFIER;
189 key_descriptor_t *d = bsearch ((void *)key, vlc_keys, vlc_num_keys,
190 sizeof (vlc_keys[0]), cmpkey);
191 if (d == NULL && utf8_cp (key, buf) == NULL)
194 if (asprintf (&str, "%s%s%s%s%s%s",
195 (code & KEY_MODIFIER_CTRL) ? "Ctrl+" : "",
196 (code & KEY_MODIFIER_ALT) ? "Alt+" : "",
197 (code & KEY_MODIFIER_SHIFT) ? "Shift+" : "",
198 (code & KEY_MODIFIER_META) ? "Meta+" : "",
199 (code & KEY_MODIFIER_COMMAND) ? "Command+" : "",
200 (d != NULL) ? d->psz_key_string : buf) == -1)
207 static int keycmp (const void *a, const void *b)
209 const struct hotkey *ka = a, *kb = b;
210 #if (INT_MAX >= 0x7fffffff)
211 return ka->i_key - kb->i_key;
213 return (ka->i_key < kb->i_key) ? -1 : (ka->i_key > kb->i_key) ? +1 : 0;
218 * Get the action ID associated with a VLC key code, if any.
221 vlc_key_t vlc_TranslateKey (const vlc_object_t *obj, uint_fast32_t keycode)
223 struct hotkey k = { .psz_action = NULL, .i_key = keycode, .i_action = 0 };
224 const struct hotkey *key;
226 key = bsearch (&k, obj->p_libvlc->p_hotkeys, libvlc_actions_count,
227 sizeof (*key), keycmp);
228 return (key != NULL) ? key->i_action : ACTIONID_NONE;
231 static int vlc_key_to_action (vlc_object_t *libvlc, const char *varname,
232 vlc_value_t prevkey, vlc_value_t curkey, void *d)
238 vlc_key_t action = vlc_TranslateKey (libvlc, curkey.i_int);
241 return var_SetInteger (libvlc, "key-action", action);
245 int vlc_InitActions (libvlc_int_t *libvlc)
249 var_Create (libvlc, "key-pressed", VLC_VAR_INTEGER);
250 var_Create (libvlc, "key-action", VLC_VAR_INTEGER);
252 keys = malloc ((libvlc_actions_count + 1) * sizeof (*keys));
255 libvlc->p_hotkeys = NULL;
259 /* Initialize from configuration */
260 for (size_t i = 0; i < libvlc_actions_count; i++)
262 keys[i].psz_action = libvlc_actions[i].name;
263 keys[i].i_key = var_InheritInteger (libvlc, libvlc_actions[i].name );
264 keys[i].i_action = libvlc_actions[i].value;
267 && strcmp (libvlc_actions[i-1].name, libvlc_actions[i].name) >= 0)
269 msg_Err (libvlc, "%s and %s are not ordered properly",
270 libvlc_actions[i-1].name, libvlc_actions[i].name);
275 qsort (keys, libvlc_actions_count, sizeof (*keys), keycmp);
277 keys[libvlc_actions_count].psz_action = NULL;
278 keys[libvlc_actions_count].i_key = 0;
279 keys[libvlc_actions_count].i_action = 0;
281 libvlc->p_hotkeys = keys;
282 var_AddCallback (libvlc, "key-pressed", vlc_key_to_action, NULL);
286 void vlc_DeinitActions (libvlc_int_t *libvlc)
288 if (unlikely(libvlc->p_hotkeys == NULL))
290 var_DelCallback (libvlc, "key-pressed", vlc_key_to_action, NULL);
291 free ((void *)libvlc->p_hotkeys);
295 static int actcmp(const void *key, const void *ent)
297 const struct action *act = ent;
298 return strcmp(key, act->name);
302 * Get the action ID from the action name in the configuration subsystem.
303 * @return the action ID or ACTIONID_NONE on error.
305 vlc_key_t vlc_GetActionId(const char *name)
307 const struct action *act;
309 act = bsearch(name, libvlc_actions, libvlc_actions_count, sizeof(*act),
311 return (act != NULL) ? act->value : ACTIONID_NONE;