--- /dev/null
+/**
+ * @file keys.c
+ * @brief X C Bindings VLC keyboard event handling
+ */
+/*****************************************************************************
+ * Copyright © 2009 Rémi Denis-Courmont
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2.0
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <xcb/xcb.h>
+#include <xcb/xcb_keysyms.h>
+#include <X11/keysym.h>
+
+#include <vlc_common.h>
+#include <vlc_keys.h>
+
+#include "xcb_vlc.h"
+
+struct key_handler_t
+{
+ vlc_object_t *obj;
+ xcb_key_symbols_t *syms;
+};
+
+/**
+ * Create an X11 key event handler for a VLC window.
+ * The caller shall arrange receiving applicable X11 events, and pass them to
+ * ProcessKeyEvent() later.
+ *
+ * @param obj VLC object owning an X window
+ * @param conn XCB connection to the X server (to fetch key mappings)
+ * @return NULL on error, or a key handling context.
+ */
+key_handler_t *CreateKeyHandler (vlc_object_t *obj, xcb_connection_t *conn)
+{
+ key_handler_t *ctx = malloc (sizeof (*ctx));
+ if (!ctx)
+ return NULL;
+
+ ctx->obj = obj;
+ ctx->syms = xcb_key_symbols_alloc (conn);
+ return ctx;
+}
+
+void DestroyKeyHandler (key_handler_t *ctx)
+{
+ xcb_key_symbols_free (ctx->syms);
+ free (ctx);
+}
+
+static int keysymcmp (const void *pa, const void *pb)
+{
+ int a = *(const xcb_keysym_t *)pa;
+ int b = *(const xcb_keysym_t *)pb;
+
+ return a - b;
+}
+
+static int ConvertKeySym (xcb_keysym_t sym)
+{
+ static const struct
+ {
+ xcb_keysym_t x11;
+ uint32_t vlc;
+ } *res, tab[] = {
+ /* This list MUST be in XK_* incremental order (see keysymdef.h),
+ * so that binary search works.
+ * Multiple X keys can match the same VLC key.
+ * X key symbols must be in the first column of the struct. */
+ { XK_BackSpace, KEY_BACKSPACE, },
+ { XK_Tab, KEY_TAB, },
+ { XK_Return, KEY_ENTER, },
+ { XK_Escape, KEY_ESC, },
+ { XK_Home, KEY_HOME, },
+ { XK_Left, KEY_LEFT, },
+ { XK_Up, KEY_UP, },
+ { XK_Right, KEY_RIGHT, },
+ { XK_Down, KEY_DOWN, },
+ { XK_Page_Up, KEY_PAGEUP, },
+ { XK_Page_Down, KEY_PAGEDOWN, },
+ { XK_End, KEY_END, },
+ { XK_Begin, KEY_HOME, },
+ { XK_Insert, KEY_INSERT, },
+ { XK_Menu, KEY_MENU },
+ { XK_KP_Space, KEY_SPACE, },
+ { XK_KP_Tab, KEY_TAB, },
+ { XK_KP_Enter, KEY_ENTER, },
+ { XK_KP_F1, KEY_F1, },
+ { XK_KP_F2, KEY_F2, },
+ { XK_KP_F3, KEY_F3, },
+ { XK_KP_F4, KEY_F4, },
+ { XK_KP_Home, KEY_HOME, },
+ { XK_KP_Left, KEY_LEFT, },
+ { XK_KP_Up, KEY_UP, },
+ { XK_KP_Right, KEY_RIGHT, },
+ { XK_KP_Down, KEY_DOWN, },
+ { XK_KP_Page_Up, KEY_PAGEUP, },
+ { XK_KP_Page_Down, KEY_PAGEDOWN, },
+ { XK_KP_End, KEY_END, },
+ { XK_KP_Begin, KEY_HOME, },
+ { XK_KP_Insert, KEY_INSERT, },
+ { XK_KP_Delete, KEY_DELETE, },
+ { XK_F1, KEY_F1, },
+ { XK_F2, KEY_F2, },
+ { XK_F3, KEY_F3, },
+ { XK_F4, KEY_F4, },
+ { XK_F5, KEY_F5, },
+ { XK_F6, KEY_F6, },
+ { XK_F7, KEY_F7, },
+ { XK_F8, KEY_F8, },
+ { XK_F9, KEY_F9, },
+ { XK_F10, KEY_F10, },
+ { XK_F11, KEY_F11, },
+ { XK_F12, KEY_F12, },
+ { XK_Delete, KEY_DELETE, },
+ };
+ /* TODO: add XF86 extensions */
+#if 0
+ KEY_BROWSER_BACK
+ KEY_BROWSER_FORWARD
+ KEY_BROWSER_REFRESH
+ KEY_BROWSER_STOP
+ KEY_BROWSER_SEARCH
+ KEY_BROWSER_FAVORITES
+ KEY_BROWSER_HOME
+ KEY_VOLUME_MUTE
+ KEY_VOLUME_DOWN
+ KEY_VOLUME_UP
+ KEY_MEDIA_NEXT_TRACK
+ KEY_MEDIA_PREV_TRACK
+ KEY_MEDIA_STOP
+ KEY_MEDIA_PLAY_PAUSE
+#endif
+
+ /* X11 and VLC both use the ASCII code for printable ASCII characters,
+ * except for space (only X11). */
+ if (sym == XK_space)
+ return KEY_SPACE;
+ if (isascii(sym))
+ return sym;
+ if (sym > XK_Delete)
+ return KEY_UNSET;
+
+ /* Special keys */
+ res = bsearch (&sym, tab, sizeof (tab) / sizeof (tab[0]), sizeof (tab[0]),
+ keysymcmp);
+ if (res != NULL)
+ return res->vlc;
+
+ return KEY_UNSET;
+}
+
+
+/**
+ * Process an X11 event, convert into VLC hotkey event if applicable.
+ *
+ * @param ctx key handler created with CreateKeyHandler()
+ * @param ev XCB event to process
+ * @return 0 if the event was handled and free()'d, non-zero otherwise
+ */
+int ProcessKeyEvent (key_handler_t *ctx, xcb_generic_event_t *ev)
+{
+ assert (ctx);
+
+ switch (ev->response_type & 0x7f)
+ {
+ case XCB_KEY_PRESS:
+ {
+ xcb_key_press_event_t *e = (xcb_key_press_event_t *)ev;
+ xcb_keysym_t sym = xcb_key_press_lookup_keysym (ctx->syms, e, 0);
+ int vk = ConvertKeySym (sym);
+
+ if (vk == KEY_UNSET)
+ break;
+ if (e->state & XCB_MOD_MASK_SHIFT)
+ vk |= KEY_MODIFIER_SHIFT;
+ if (e->state & XCB_MOD_MASK_CONTROL)
+ vk |= KEY_MODIFIER_CTRL;
+ if (e->state & XCB_MOD_MASK_1)
+ vk |= KEY_MODIFIER_ALT;
+ if (e->state & XCB_MOD_MASK_4)
+ vk |= KEY_MODIFIER_COMMAND;
+ var_SetInteger (ctx->obj->p_libvlc, "key-pressed", vk);
+ break;
+ }
+
+ case XCB_KEY_RELEASE:
+ break;
+
+ /*TODO: key mappings update*/
+ default:
+ return -1;
+ }
+
+ free (ev);
+ return 0;
+}