]> git.sesse.net Git - vlc/blob - modules/video_output/xcb/keys.c
XCB key press handling
[vlc] / 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 General Public License
10  * as published by the Free Software Foundation; either version 2.0
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
36 #include <vlc_common.h>
37 #include <vlc_keys.h>
38
39 #include "xcb_vlc.h"
40
41 struct key_handler_t
42 {
43     vlc_object_t      *obj;
44     xcb_key_symbols_t *syms;
45 };
46
47 /**
48  * Create an X11 key event handler for a VLC window.
49  * The caller shall arrange receiving applicable X11 events, and pass them to
50  * ProcessKeyEvent() later.
51  *
52  * @param obj VLC object owning an X window
53  * @param conn XCB connection to the X server (to fetch key mappings)
54  * @return NULL on error, or a key handling context.
55  */
56 key_handler_t *CreateKeyHandler (vlc_object_t *obj, xcb_connection_t *conn)
57 {
58     key_handler_t *ctx = malloc (sizeof (*ctx));
59     if (!ctx)
60         return NULL;
61
62     ctx->obj = obj;
63     ctx->syms = xcb_key_symbols_alloc (conn);
64     return ctx;
65 }
66
67 void DestroyKeyHandler (key_handler_t *ctx)
68 {
69     xcb_key_symbols_free (ctx->syms);
70     free (ctx);
71 }
72
73 static int keysymcmp (const void *pa, const void *pb)
74 {
75     int a = *(const xcb_keysym_t *)pa;
76     int b = *(const xcb_keysym_t *)pb;
77
78     return a - b;
79 }
80
81 static int ConvertKeySym (xcb_keysym_t sym)
82 {
83     static const struct
84     {
85         xcb_keysym_t x11;
86         uint32_t vlc;
87     } *res, tab[] = {
88     /* This list MUST be in XK_* incremental order (see keysymdef.h),
89      * so that binary search works.
90      * Multiple X keys can match the same VLC key.
91      * X key symbols must be in the first column of the struct. */
92         { XK_BackSpace,     KEY_BACKSPACE, },
93         { XK_Tab,           KEY_TAB, },
94         { XK_Return,        KEY_ENTER, },
95         { XK_Escape,        KEY_ESC, },
96         { XK_Home,          KEY_HOME, },
97         { XK_Left,          KEY_LEFT, },
98         { XK_Up,            KEY_UP, },
99         { XK_Right,         KEY_RIGHT, },
100         { XK_Down,          KEY_DOWN, },
101         { XK_Page_Up,       KEY_PAGEUP, },
102         { XK_Page_Down,     KEY_PAGEDOWN, },
103         { XK_End,           KEY_END, },
104         { XK_Begin,         KEY_HOME, },
105         { XK_Insert,        KEY_INSERT, },
106         { XK_Menu,          KEY_MENU },
107         { XK_KP_Space,      KEY_SPACE, },
108         { XK_KP_Tab,        KEY_TAB, },
109         { XK_KP_Enter,      KEY_ENTER, },
110         { XK_KP_F1,         KEY_F1, },
111         { XK_KP_F2,         KEY_F2, },
112         { XK_KP_F3,         KEY_F3, },
113         { XK_KP_F4,         KEY_F4, },
114         { XK_KP_Home,       KEY_HOME, },
115         { XK_KP_Left,       KEY_LEFT, },
116         { XK_KP_Up,         KEY_UP, },
117         { XK_KP_Right,      KEY_RIGHT, },
118         { XK_KP_Down,       KEY_DOWN, },
119         { XK_KP_Page_Up,    KEY_PAGEUP, },
120         { XK_KP_Page_Down,  KEY_PAGEDOWN, },
121         { XK_KP_End,        KEY_END, },
122         { XK_KP_Begin,      KEY_HOME, },
123         { XK_KP_Insert,     KEY_INSERT, },
124         { XK_KP_Delete,     KEY_DELETE, },
125         { XK_F1,            KEY_F1, },
126         { XK_F2,            KEY_F2, },
127         { XK_F3,            KEY_F3, },
128         { XK_F4,            KEY_F4, },
129         { XK_F5,            KEY_F5, },
130         { XK_F6,            KEY_F6, },
131         { XK_F7,            KEY_F7, },
132         { XK_F8,            KEY_F8, },
133         { XK_F9,            KEY_F9, },
134         { XK_F10,           KEY_F10, },
135         { XK_F11,           KEY_F11, },
136         { XK_F12,           KEY_F12, },
137         { XK_Delete,        KEY_DELETE, },
138     };
139     /* TODO: add XF86 extensions */
140 #if 0
141     KEY_BROWSER_BACK
142     KEY_BROWSER_FORWARD
143     KEY_BROWSER_REFRESH
144     KEY_BROWSER_STOP
145     KEY_BROWSER_SEARCH
146     KEY_BROWSER_FAVORITES
147     KEY_BROWSER_HOME
148     KEY_VOLUME_MUTE
149     KEY_VOLUME_DOWN
150     KEY_VOLUME_UP
151     KEY_MEDIA_NEXT_TRACK
152     KEY_MEDIA_PREV_TRACK
153     KEY_MEDIA_STOP
154     KEY_MEDIA_PLAY_PAUSE
155 #endif
156
157     /* X11 and VLC both use the ASCII code for printable ASCII characters,
158      * except for space (only X11). */
159     if (sym == XK_space)
160         return KEY_SPACE;
161     if (isascii(sym))
162         return sym;
163     if (sym > XK_Delete)
164         return KEY_UNSET;
165
166     /* Special keys */
167     res = bsearch (&sym, tab, sizeof (tab) / sizeof (tab[0]), sizeof (tab[0]),
168                    keysymcmp);
169     if (res != NULL)
170         return res->vlc;
171
172     return KEY_UNSET;
173 }
174
175
176 /**
177  * Process an X11 event, convert into VLC hotkey event if applicable.
178  *
179  * @param ctx key handler created with CreateKeyHandler()
180  * @param ev XCB event to process
181  * @return 0 if the event was handled and free()'d, non-zero otherwise
182  */
183 int ProcessKeyEvent (key_handler_t *ctx, xcb_generic_event_t *ev)
184 {
185     assert (ctx);
186
187     switch (ev->response_type & 0x7f)
188     {
189         case XCB_KEY_PRESS:
190         {
191             xcb_key_press_event_t *e = (xcb_key_press_event_t *)ev;
192             xcb_keysym_t sym = xcb_key_press_lookup_keysym (ctx->syms, e, 0);
193             int vk = ConvertKeySym (sym);
194
195             if (vk == KEY_UNSET)
196                 break;
197             if (e->state & XCB_MOD_MASK_SHIFT)
198                 vk |= KEY_MODIFIER_SHIFT;
199             if (e->state & XCB_MOD_MASK_CONTROL)
200                 vk |= KEY_MODIFIER_CTRL;
201             if (e->state & XCB_MOD_MASK_1)
202                 vk |= KEY_MODIFIER_ALT;
203             if (e->state & XCB_MOD_MASK_4)
204                 vk |= KEY_MODIFIER_COMMAND;
205             var_SetInteger (ctx->obj->p_libvlc, "key-pressed", vk);
206             break;
207         }
208
209         case XCB_KEY_RELEASE:
210             break;
211
212         /*TODO: key mappings update*/
213         default:
214             return -1;
215     }
216
217     free (ev);
218     return 0;
219 }