0669129af5315196933b61013a6a44584bbd8670
[vlc.git] / modules / video_output / xcb / keys.c
1 /**
2  * @file keys.c
3  * @brief X C Bindings VLC keyboard event handling
4  */
5 /*****************************************************************************
6  * Copyright © 2009 Rémi Denis-Courmont
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1
11  * of the License, or (at your option) any later version.
12  *
13  * This library 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 Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  ****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <stdlib.h>
28 #include <inttypes.h>
29 #include <ctype.h>
30 #include <assert.h>
31
32 #include <xcb/xcb.h>
33 #include <xcb/xcb_keysyms.h>
34 #include <X11/keysym.h>
35 #include <X11/XF86keysym.h>
36
37 #include <vlc_common.h>
38 #include <vlc_keys.h>
39
40 #include "xcb_vlc.h"
41
42 struct key_handler_t
43 {
44     vlc_object_t      *obj;
45     xcb_key_symbols_t *syms;
46 };
47
48 /**
49  * Create an X11 key event handler for a VLC window.
50  * The caller shall arrange receiving applicable X11 events, and pass them to
51  * ProcessKeyEvent() later.
52  *
53  * @param obj VLC object owning an X window
54  * @param conn XCB connection to the X server (to fetch key mappings)
55  * @return NULL on error, or a key handling context.
56  */
57 key_handler_t *CreateKeyHandler (vlc_object_t *obj, xcb_connection_t *conn)
58 {
59     key_handler_t *ctx = malloc (sizeof (*ctx));
60     if (!ctx)
61         return NULL;
62
63     ctx->obj = obj;
64     ctx->syms = xcb_key_symbols_alloc (conn);
65     return ctx;
66 }
67
68 void DestroyKeyHandler (key_handler_t *ctx)
69 {
70     xcb_key_symbols_free (ctx->syms);
71     free (ctx);
72 }
73
74 static int keysymcmp (const void *pa, const void *pb)
75 {
76     int a = *(const xcb_keysym_t *)pa;
77     int b = *(const xcb_keysym_t *)pb;
78
79     return a - b;
80 }
81
82 static int ConvertKeySym (xcb_keysym_t sym)
83 {
84     static const struct
85     {
86         xcb_keysym_t x11;
87         uint32_t vlc;
88     } *res, tab[] = {
89     /* This list MUST be in XK_* incremental order (see keysymdef.h),
90      * so that binary search works.
91      * Multiple X keys can match the same VLC key.
92      * X key symbols must be in the first column of the struct. */
93         { XK_BackSpace,     KEY_BACKSPACE, },
94         { XK_Tab,           KEY_TAB, },
95         { XK_Return,        KEY_ENTER, },
96         { XK_Escape,        KEY_ESC, },
97         { XK_Home,          KEY_HOME, },
98         { XK_Left,          KEY_LEFT, },
99         { XK_Up,            KEY_UP, },
100         { XK_Right,         KEY_RIGHT, },
101         { XK_Down,          KEY_DOWN, },
102         { XK_Page_Up,       KEY_PAGEUP, },
103         { XK_Page_Down,     KEY_PAGEDOWN, },
104         { XK_End,           KEY_END, },
105         { XK_Begin,         KEY_HOME, },
106         { XK_Insert,        KEY_INSERT, },
107         { XK_Menu,          KEY_MENU },
108         { XK_KP_Space,      ' ', },
109         { XK_KP_Tab,        KEY_TAB, },
110         { XK_KP_Enter,      KEY_ENTER, },
111         { XK_KP_F1,         KEY_F1, },
112         { XK_KP_F2,         KEY_F2, },
113         { XK_KP_F3,         KEY_F3, },
114         { XK_KP_F4,         KEY_F4, },
115         { XK_KP_Home,       KEY_HOME, },
116         { XK_KP_Left,       KEY_LEFT, },
117         { XK_KP_Up,         KEY_UP, },
118         { XK_KP_Right,      KEY_RIGHT, },
119         { XK_KP_Down,       KEY_DOWN, },
120         { XK_KP_Page_Up,    KEY_PAGEUP, },
121         { XK_KP_Page_Down,  KEY_PAGEDOWN, },
122         { XK_KP_End,        KEY_END, },
123         { XK_KP_Begin,      KEY_HOME, },
124         { XK_KP_Insert,     KEY_INSERT, },
125         { XK_KP_Delete,     KEY_DELETE, },
126         { XK_F1,            KEY_F1, },
127         { XK_F2,            KEY_F2, },
128         { XK_F3,            KEY_F3, },
129         { XK_F4,            KEY_F4, },
130         { XK_F5,            KEY_F5, },
131         { XK_F6,            KEY_F6, },
132         { XK_F7,            KEY_F7, },
133         { XK_F8,            KEY_F8, },
134         { XK_F9,            KEY_F9, },
135         { XK_F10,           KEY_F10, },
136         { XK_F11,           KEY_F11, },
137         { XK_F12,           KEY_F12, },
138         { XK_Delete,        KEY_DELETE, },
139
140         /* XFree86 extensions */
141         { XF86XK_AudioLowerVolume, KEY_VOLUME_DOWN, },
142         { XF86XK_AudioMute,        KEY_VOLUME_MUTE, },
143         { XF86XK_AudioRaiseVolume, KEY_VOLUME_UP, },
144         { XF86XK_AudioPlay,        KEY_MEDIA_PLAY_PAUSE, },
145         { XF86XK_AudioStop,        KEY_MEDIA_STOP, },
146         { XF86XK_AudioPrev,        KEY_MEDIA_PREV_TRACK, },
147         { XF86XK_AudioNext,        KEY_MEDIA_NEXT_TRACK, },
148         { XF86XK_HomePage,         KEY_BROWSER_HOME, },
149         { XF86XK_Search,           KEY_BROWSER_SEARCH, },
150         { XF86XK_Back,             KEY_BROWSER_BACK, },
151         { XF86XK_Forward,          KEY_BROWSER_FORWARD, },
152         { XF86XK_Stop,             KEY_BROWSER_STOP, },
153         { XF86XK_Refresh,          KEY_BROWSER_REFRESH, },
154         { XF86XK_Favorites,        KEY_BROWSER_FAVORITES, },
155         { XF86XK_AudioPause,       KEY_MEDIA_PLAY_PAUSE, },
156         { XF86XK_Reload,           KEY_BROWSER_REFRESH, },
157     };
158
159     /* X11 and VLC both use the ASCII code for printable ASCII characters. */
160     if (isascii(sym))
161         return sym;
162
163     /* Special keys */
164     res = bsearch (&sym, tab, sizeof (tab) / sizeof (tab[0]), sizeof (tab[0]),
165                    keysymcmp);
166     if (res != NULL)
167         return res->vlc;
168
169     return KEY_UNSET;
170 }
171
172
173 /**
174  * Process an X11 event, convert into VLC hotkey event if applicable.
175  *
176  * @param ctx key handler created with CreateKeyHandler()
177  * @param ev XCB event to process
178  * @return 0 if the event was handled and free()'d, non-zero otherwise
179  */
180 int ProcessKeyEvent (key_handler_t *ctx, xcb_generic_event_t *ev)
181 {
182     assert (ctx);
183
184     switch (ev->response_type & 0x7f)
185     {
186         case XCB_KEY_PRESS:
187         {
188             xcb_key_press_event_t *e = (xcb_key_press_event_t *)ev;
189             xcb_keysym_t sym = xcb_key_press_lookup_keysym (ctx->syms, e, 0);
190             int vk = ConvertKeySym (sym);
191
192             if (vk == KEY_UNSET)
193                 break;
194             if (e->state & XCB_MOD_MASK_SHIFT)
195                 vk |= KEY_MODIFIER_SHIFT;
196             if (e->state & XCB_MOD_MASK_CONTROL)
197                 vk |= KEY_MODIFIER_CTRL;
198             if (e->state & XCB_MOD_MASK_1)
199                 vk |= KEY_MODIFIER_ALT;
200             if (e->state & XCB_MOD_MASK_4)
201                 vk |= KEY_MODIFIER_COMMAND;
202             var_SetInteger (ctx->obj->p_libvlc, "key-pressed", vk);
203             break;
204         }
205
206         case XCB_KEY_RELEASE:
207             break;
208
209         case XCB_MAPPING_NOTIFY:
210         {
211             xcb_mapping_notify_event_t *e = (xcb_mapping_notify_event_t *)ev;
212             msg_Dbg (ctx->obj, "refreshing keyboard mapping");
213             xcb_refresh_keyboard_mapping (ctx->syms, e);
214             break;
215         }
216
217         default:
218             return -1;
219     }
220
221     free (ev);
222     return 0;
223 }