]> git.sesse.net Git - vlc/blob - src/config/keys.c
core: merge the two hotkey files
[vlc] / src / config / keys.c
1 /*****************************************************************************
2  * keys.c: keys configuration
3  *****************************************************************************
4  * Copyright (C) 2003-2009 the VideoLAN team
5  *
6  * Authors: Sigmund Augdal Helberg <dnumgis@videolan.org>
7  *
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.
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 General Public License for more details.
17  *
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  *****************************************************************************/
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
39 #include <vlc_common.h>
40 #include <vlc_keys.h>
41 #include "configuration.h"
42 #include "libvlc.h"
43
44 typedef struct key_descriptor_s
45 {
46     const char psz_key_string[20];
47     uint32_t i_key_code;
48 } key_descriptor_t;
49
50 static const struct key_descriptor_s vlc_keys[] =
51 {
52     { "Unset", KEY_UNSET },
53     { "Backspace", KEY_BACKSPACE },
54     { "Tab", KEY_TAB },
55     { "Enter", KEY_ENTER },
56     { "Esc", KEY_ESC },
57     { "Space", ' ' },
58     { "Left", KEY_LEFT },
59     { "Right", KEY_RIGHT },
60     { "Up", KEY_UP },
61     { "Down", KEY_DOWN },
62     { "F1", KEY_F1 },
63     { "F2", KEY_F2 },
64     { "F3", KEY_F3 },
65     { "F4", KEY_F4 },
66     { "F5", KEY_F5 },
67     { "F6", KEY_F6 },
68     { "F7", KEY_F7 },
69     { "F8", KEY_F8 },
70     { "F9", KEY_F9 },
71     { "F10", KEY_F10 },
72     { "F11", KEY_F11 },
73     { "F12", KEY_F12 },
74     { "Home", KEY_HOME },
75     { "End", KEY_END },
76     { "Insert", KEY_INSERT },
77     { "Delete", KEY_DELETE },
78     { "Menu", KEY_MENU },
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 },
99 };
100 enum { vlc_num_keys=sizeof(vlc_keys)/sizeof(struct key_descriptor_s) };
101
102 static int cmpkey (const void *key, const void *elem)
103 {
104     return ((uintptr_t)key) - ((key_descriptor_t *)elem)->i_key_code;
105 }
106
107 /* Convert Unicode code point to UTF-8 */
108 static char *utf8_cp (uint_fast32_t cp, char *buf)
109 {
110     if (cp < (1 << 7))
111     {
112         buf[1] = 0;
113         buf[0] = cp;
114     }
115     else if (cp < (1 << 11))
116     {
117         buf[2] = 0;
118         buf[1] = 0x80 | (cp & 0x3F);
119         cp >>= 6;
120         buf[0] = 0xC0 | cp;
121     }
122     else if (cp < (1 << 16))
123     {
124         buf[3] = 0;
125         buf[2] = 0x80 | (cp & 0x3F);
126         cp >>= 6;
127         buf[1] = 0x80 | (cp & 0x3F);
128         cp >>= 6;
129         buf[0] = 0xE0 | cp;
130     }
131     else if (cp < (1 << 21))
132     {
133         buf[4] = 0;
134         buf[3] = 0x80 | (cp & 0x3F);
135         cp >>= 6;
136         buf[2] = 0x80 | (cp & 0x3F);
137         cp >>= 6;
138         buf[1] = 0x80 | (cp & 0x3F);
139         cp >>= 6;
140         buf[0] = 0xE0 | cp;
141     }
142     else
143         return NULL;
144     return buf;
145 }
146
147 uint_fast32_t ConfigStringToKey (const char *name)
148 {
149     uint_fast32_t mods = 0;
150     uint32_t cp;
151
152     for (;;)
153     {
154         size_t len = strcspn (name, "-+");
155         if (len == 0 || name[len] == '\0')
156             break;
157
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;
168
169         name += len + 1;
170     }
171
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;
175
176     return (vlc_towc (name, &cp) > 0) ? (mods | cp) : KEY_UNSET;
177 }
178
179 char *vlc_keycode2str (uint_fast32_t code)
180 {
181     char *str, buf[5];
182     uintptr_t key = code & ~KEY_MODIFIER;
183
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)
187         return NULL;
188
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)
196         return NULL;
197
198     return str;
199 }
200
201
202 static int keycmp (const void *a, const void *b)
203 {
204     const struct hotkey *ka = a, *kb = b;
205 #if (INT_MAX >= 0x7fffffff)
206     return ka->i_key - kb->i_key;
207 #else
208     return (ka->i_key < kb->i_key) ? -1 : (ka->i_key > kb->i_key) ? +1 : 0;
209 #endif
210 }
211
212 /**
213  * Get the action associated with a VLC key code, if any.
214  */
215 static
216 vlc_key_t vlc_TranslateKey (const vlc_object_t *obj, uint_fast32_t keycode)
217 {
218     struct hotkey k = { .psz_action = NULL, .i_key = keycode, .i_action = 0 };
219     const struct hotkey *key;
220
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;
224 }
225
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)
228 {
229     (void)varname;
230     (void)prevkey;
231     (void)d;
232
233     vlc_key_t action = vlc_TranslateKey (libvlc, curkey.i_int);
234     if (!action)
235         return VLC_SUCCESS;
236     return var_SetInteger (libvlc, "key-action", action);
237 }
238
239
240 int vlc_InitActions (libvlc_int_t *libvlc)
241 {
242     struct hotkey *keys;
243
244     var_Create (libvlc, "key-pressed", VLC_VAR_INTEGER);
245     var_Create (libvlc, "key-action", VLC_VAR_INTEGER);
246
247     keys = malloc ((libvlc_actions_count + 1) * sizeof (*keys));
248     if (keys == NULL)
249     {
250         libvlc->p_hotkeys = NULL;
251         return VLC_ENOMEM;
252     }
253
254     /* Initialize from configuration */
255     for (size_t i = 0; i < libvlc_actions_count; i++)
256     {
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;
260 #ifndef NDEBUG
261         if (i > 0
262          && strcmp (libvlc_actions[i-1].name, libvlc_actions[i].name) >= 0)
263         {
264             msg_Err (libvlc, "%s and %s are not ordered properly",
265                      libvlc_actions[i-1].name, libvlc_actions[i].name);
266             abort ();
267         }
268 #endif
269     }
270     qsort (keys, libvlc_actions_count, sizeof (*keys), keycmp);
271
272     keys[libvlc_actions_count].psz_action = NULL;
273     keys[libvlc_actions_count].i_key = 0;
274     keys[libvlc_actions_count].i_action = 0;
275
276     libvlc->p_hotkeys = keys;
277     var_AddCallback (libvlc, "key-pressed", vlc_key_to_action, NULL);
278     return VLC_SUCCESS;
279 }
280
281 void vlc_DeinitActions (libvlc_int_t *libvlc)
282 {
283     if (unlikely(libvlc->p_hotkeys == NULL))
284         return;
285     var_DelCallback (libvlc, "key-pressed", vlc_key_to_action, NULL);
286     free ((void *)libvlc->p_hotkeys);
287 }
288
289
290 static int actcmp(const void *key, const void *ent)
291 {
292     const struct action *act = ent;
293     return strcmp(key, act->name);
294 }
295
296 vlc_key_t vlc_GetActionId(const char *name)
297 {
298     const struct action *act;
299
300     act = bsearch(name, libvlc_actions, libvlc_actions_count, sizeof(*act),
301                   actcmp);
302     return (act != NULL) ? act->value : ACTIONID_NONE;
303 }