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;
179 char *vlc_keycode2str (uint_fast32_t code)
182 uintptr_t key = code & ~KEY_MODIFIER;
184 key_descriptor_t *d = bsearch ((void *)key, vlc_keys, vlc_num_keys,
185 sizeof (vlc_keys[0]), cmpkey);
186 if (d == NULL && utf8_cp (key, buf) == NULL)
189 if (asprintf (&str, "%s%s%s%s%s%s",
190 (code & KEY_MODIFIER_CTRL) ? "Ctrl+" : "",
191 (code & KEY_MODIFIER_ALT) ? "Alt+" : "",
192 (code & KEY_MODIFIER_SHIFT) ? "Shift+" : "",
193 (code & KEY_MODIFIER_META) ? "Meta+" : "",
194 (code & KEY_MODIFIER_COMMAND) ? "Command+" : "",
195 (d != NULL) ? d->psz_key_string : buf) == -1)
202 static int keycmp (const void *a, const void *b)
204 const struct hotkey *ka = a, *kb = b;
205 #if (INT_MAX >= 0x7fffffff)
206 return ka->i_key - kb->i_key;
208 return (ka->i_key < kb->i_key) ? -1 : (ka->i_key > kb->i_key) ? +1 : 0;
213 * Get the action associated with a VLC key code, if any.
216 vlc_key_t vlc_TranslateKey (const vlc_object_t *obj, uint_fast32_t keycode)
218 struct hotkey k = { .psz_action = NULL, .i_key = keycode, .i_action = 0 };
219 const struct hotkey *key;
221 key = bsearch (&k, obj->p_libvlc->p_hotkeys, libvlc_actions_count,
222 sizeof (*key), keycmp);
223 return (key != NULL) ? key->i_action : ACTIONID_NONE;
226 static int vlc_key_to_action (vlc_object_t *libvlc, const char *varname,
227 vlc_value_t prevkey, vlc_value_t curkey, void *d)
233 vlc_key_t action = vlc_TranslateKey (libvlc, curkey.i_int);
236 return var_SetInteger (libvlc, "key-action", action);
240 int vlc_InitActions (libvlc_int_t *libvlc)
244 var_Create (libvlc, "key-pressed", VLC_VAR_INTEGER);
245 var_Create (libvlc, "key-action", VLC_VAR_INTEGER);
247 keys = malloc ((libvlc_actions_count + 1) * sizeof (*keys));
250 libvlc->p_hotkeys = NULL;
254 /* Initialize from configuration */
255 for (size_t i = 0; i < libvlc_actions_count; i++)
257 keys[i].psz_action = libvlc_actions[i].name;
258 keys[i].i_key = var_InheritInteger (libvlc, libvlc_actions[i].name );
259 keys[i].i_action = libvlc_actions[i].value;
262 && strcmp (libvlc_actions[i-1].name, libvlc_actions[i].name) >= 0)
264 msg_Err (libvlc, "%s and %s are not ordered properly",
265 libvlc_actions[i-1].name, libvlc_actions[i].name);
270 qsort (keys, libvlc_actions_count, sizeof (*keys), keycmp);
272 keys[libvlc_actions_count].psz_action = NULL;
273 keys[libvlc_actions_count].i_key = 0;
274 keys[libvlc_actions_count].i_action = 0;
276 libvlc->p_hotkeys = keys;
277 var_AddCallback (libvlc, "key-pressed", vlc_key_to_action, NULL);
281 void vlc_DeinitActions (libvlc_int_t *libvlc)
283 if (unlikely(libvlc->p_hotkeys == NULL))
285 var_DelCallback (libvlc, "key-pressed", vlc_key_to_action, NULL);
286 free ((void *)libvlc->p_hotkeys);
290 static int actcmp(const void *key, const void *ent)
292 const struct action *act = ent;
293 return strcmp(key, act->name);
296 vlc_key_t vlc_GetActionId(const char *name)
298 const struct action *act;
300 act = bsearch(name, libvlc_actions, libvlc_actions_count, sizeof(*act),
302 return (act != NULL) ? act->value : ACTIONID_NONE;