]> git.sesse.net Git - vlc/commitdiff
Converted vout caca to "vout display" API.
authorLaurent Aimar <fenrir@videolan.org>
Mon, 3 Aug 2009 18:52:37 +0000 (20:52 +0200)
committerLaurent Aimar <fenrir@videolan.org>
Tue, 4 Aug 2009 19:03:24 +0000 (21:03 +0200)
modules/video_output/caca.c

index d044a3d5ea0aff0a9caac7bfaca1fcddac107233..d8e1a54ae2a1241514beb90b732e2036623ca3ef 100644 (file)
@@ -1,10 +1,11 @@
 /*****************************************************************************
- * caca.c: Color ASCII Art video output plugin using libcaca
+ * caca.c: Color ASCII Art "vout display" module using libcaca
  *****************************************************************************
  * Copyright (C) 2003-2009 the VideoLAN team
  * $Id$
  *
  * Authors: Sam Hocevar <sam@zoy.org>
+ *          Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 #include <vlc_common.h>
 #include <vlc_plugin.h>
-#include <vlc_vout.h>
-#include <vlc_interface.h>
-#include <vlc_playlist.h>
-#include <vlc_keys.h>
+#include <vlc_vout_display.h>
+#include <vlc_picture_pool.h>
 
 #include <caca.h>
 
-#ifndef CACA_API_VERSION_1
-    /* Upward compatibility macros */
-    typedef char cucul_canvas_t;
-    typedef struct caca_bitmap cucul_dither_t;
-    typedef char caca_display_t;
-#   define CUCUL_COLOR_DEFAULT CACA_COLOR_LIGHTGRAY
-#   define CUCUL_COLOR_BLACK CACA_COLOR_BLACK
-#   define cucul_clear_canvas(x) caca_clear()
-#   define cucul_create_canvas(x,y) "" /* kinda hacky */
-#   define cucul_create_dither caca_create_bitmap
-#   define cucul_dither_bitmap(x,y,z,t,u,v,w) caca_draw_bitmap(y,z,t,u,v,w)
-#   define cucul_free_dither caca_free_bitmap
-#   define cucul_free_canvas(x)
-#   define cucul_get_canvas_width(x) caca_get_width()
-#   define cucul_get_canvas_height(x) caca_get_height()
-#   define cucul_set_color(x,y,z) caca_set_color(y,z)
-#   define caca_create_display(x) (caca_init() ? NULL : "") /* hacky, too */
-#   define caca_free_display(x) caca_end()
-#   define caca_get_event(x,y,z,t) *(z) = caca_get_event(y)
-#   define caca_refresh_display(x) caca_refresh()
-#   define caca_set_display_title(x,y) caca_set_window_title(y)
-#endif
-
-/*****************************************************************************
- * Local prototypes
- *****************************************************************************/
-static int  Create    ( vlc_object_t * );
-static void Destroy   ( vlc_object_t * );
-
-static int  Init      ( vout_thread_t * );
-static void End       ( vout_thread_t * );
-static int  Manage    ( vout_thread_t * );
-static void Render    ( vout_thread_t *, picture_t * );
-static void Display   ( vout_thread_t *, picture_t * );
-
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
-vlc_module_begin ()
-    set_shortname( "Caca" )
-    set_category( CAT_VIDEO )
-    set_subcategory( SUBCAT_VIDEO_VOUT )
-    set_description( N_("Color ASCII art video output") )
-    set_capability( "video output", 12 )
-    set_callbacks( Create, Destroy )
-vlc_module_end ()
+static int  Open (vlc_object_t *);
+static void Close(vlc_object_t *);
+
+vlc_module_begin()
+    set_shortname("Caca")
+    set_category(CAT_VIDEO)
+    set_subcategory(SUBCAT_VIDEO_VOUT)
+    set_description(N_("Color ASCII art video output"))
+    set_capability("vout display", 12)
+    set_callbacks(Open, Close)
+vlc_module_end()
 
 /*****************************************************************************
- * vout_sys_t: libcaca video output method descriptor
- *****************************************************************************
- * This structure is part of the video output thread descriptor.
- * It describes the libcaca specific properties of an output thread.
+ * Local prototypes
  *****************************************************************************/
-struct vout_sys_t
-{
-    cucul_canvas_t *p_cv;
-    caca_display_t *p_dp;
-    cucul_dither_t *p_dither;
+static picture_t *Get    (vout_display_t *);
+static void       Prepare(vout_display_t *, picture_t *);
+static void       Display(vout_display_t *, picture_t *);
+static int        Control(vout_display_t *, int, va_list);
+
+/* */
+static void Manage(vout_display_t *);
+static void Refresh(vout_display_t *);
+static void Place(vout_display_t *, vout_display_place_t *);
+
+/* */
+struct vout_display_sys_t {
+    cucul_canvas_t *cv;
+    caca_display_t *dp;
+    cucul_dither_t *dither;
+
+    picture_pool_t *pool;
 };
 
-/*****************************************************************************
- * Create: allocates libcaca video output thread
- *****************************************************************************
+/**
  * This function initializes libcaca vout method.
- *****************************************************************************/
-static int Create( vlc_object_t *p_this )
+ */
+static int Open(vlc_object_t *object)
 {
-    vout_thread_t *p_vout = (vout_thread_t *)p_this;
+    vout_display_t *vd = (vout_display_t *)object;
+    vout_display_sys_t *sys;
 
-#if defined( WIN32 ) && !defined( UNDER_CE )
+#if defined(WIN32) && !defined(UNDER_CE)
     CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
     SMALL_RECT rect;
     COORD coord;
     HANDLE hstdout;
 
-    if( !AllocConsole() )
-    {
-        msg_Err( p_vout, "cannot create console" );
+    if (!AllocConsole()) {
+        msg_Err(vd, "cannot create console");
         return VLC_EGENERIC;
     }
 
     hstdout =
-        CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE,
-                                   FILE_SHARE_READ | FILE_SHARE_WRITE,
-                                   NULL, CONSOLE_TEXTMODE_BUFFER, NULL );
-    if( !hstdout || hstdout == INVALID_HANDLE_VALUE )
-    {
-        msg_Err( p_vout, "cannot create screen buffer" );
+        CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
+                                  FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                  NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
+    if (!hstdout || hstdout == INVALID_HANDLE_VALUE) {
+        msg_Err(vd, "cannot create screen buffer");
         FreeConsole();
         return VLC_EGENERIC;
     }
 
-    if( !SetConsoleActiveScreenBuffer( hstdout) )
-    {
-        msg_Err( p_vout, "cannot set active screen buffer" );
+    if (!SetConsoleActiveScreenBuffer(hstdout)) {
+        msg_Err(vd, "cannot set active screen buffer");
         FreeConsole();
         return VLC_EGENERIC;
     }
 
-    coord = GetLargestConsoleWindowSize( hstdout );
-    msg_Dbg( p_vout, "SetConsoleWindowInfo: %ix%i", coord.X, coord.Y );
+    coord = GetLargestConsoleWindowSize(hstdout);
+    msg_Dbg(vd, "SetConsoleWindowInfo: %ix%i", coord.X, coord.Y);
 
     /* Force size for now */
     coord.X = 100;
     coord.Y = 40;
 
-    if( !SetConsoleScreenBufferSize( hstdout, coord ) )
-        msg_Warn( p_vout, "SetConsoleScreenBufferSize %i %i",
-                  coord.X, coord.Y );
+    if (!SetConsoleScreenBufferSize(hstdout, coord))
+        msg_Warn(vd, "SetConsoleScreenBufferSize %i %i",
+                  coord.X, coord.Y);
 
     /* Get the current screen buffer size and window position. */
-    if( GetConsoleScreenBufferInfo( hstdout, &csbiInfo ) )
-    {
+    if (GetConsoleScreenBufferInfo(hstdout, &csbiInfo)) {
         rect.Top = 0; rect.Left = 0;
         rect.Right = csbiInfo.dwMaximumWindowSize.X - 1;
         rect.Bottom = csbiInfo.dwMaximumWindowSize.Y - 1;
-        if( !SetConsoleWindowInfo( hstdout, TRUE, &rect ) )
-            msg_Dbg( p_vout, "SetConsoleWindowInfo failed: %ix%i",
-                     rect.Right, rect.Bottom );
+        if (!SetConsoleWindowInfo(hstdout, TRUE, &rect))
+            msg_Dbg(vd, "SetConsoleWindowInfo failed: %ix%i",
+                     rect.Right, rect.Bottom);
     }
 #endif
 
     /* Allocate structure */
-    p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
-    if( p_vout->p_sys == NULL )
-    {
-#if defined( WIN32 ) && !defined( UNDER_CE )
-        FreeConsole();
-#endif
-        return VLC_ENOMEM;
+    vd->sys = sys = calloc(1, sizeof(*sys));
+    if (!sys)
+        goto error;
+
+    sys->cv = cucul_create_canvas(0, 0);
+    if (!sys->cv) {
+        msg_Err(vd, "cannot initialize libcucul");
+        goto error;
     }
 
-    p_vout->p_sys->p_cv = cucul_create_canvas(0, 0);
-    if( !p_vout->p_sys->p_cv )
-    {
-        msg_Err( p_vout, "cannot initialize libcucul" );
-#if defined( WIN32 ) && !defined( UNDER_CE )
-        FreeConsole();
-#endif
-        free( p_vout->p_sys );
-        return VLC_EGENERIC;
+    sys->dp = caca_create_display(sys->cv);
+    if (!sys->dp) {
+        msg_Err(vd, "cannot initialize libcaca");
+        goto error;
     }
 
-    p_vout->p_sys->p_dp = caca_create_display( p_vout->p_sys->p_cv );
-    if( !p_vout->p_sys->p_dp )
-    {
-        msg_Err( p_vout, "cannot initialize libcaca" );
-        cucul_free_canvas( p_vout->p_sys->p_cv );
-#if defined( WIN32 ) && !defined( UNDER_CE )
-        FreeConsole();
-#endif
-        free( p_vout->p_sys );
-        return VLC_EGENERIC;
+    if (vd->cfg->display.title)
+        caca_set_display_title(sys->dp,
+                               vd->cfg->display.title);
+    else
+        caca_set_display_title(sys->dp,
+                               VOUT_TITLE "(Colour AsCii Art)");
+
+    /* Fix format */
+    video_format_t fmt = vd->fmt;
+    if (fmt.i_chroma != VLC_CODEC_RGB32) {
+        fmt.i_chroma = VLC_CODEC_RGB32;
+        fmt.i_rmask = 0x00ff0000;
+        fmt.i_gmask = 0x0000ff00;
+        fmt.i_bmask = 0x000000ff;
     }
 
-    caca_set_display_title( p_vout->p_sys->p_dp,
-                            VOUT_TITLE " - Colour AsCii Art (caca)" );
+    /* */
+    sys->pool = picture_pool_NewFromFormat(&fmt, 1);
+    if (!sys->pool)
+        goto error;
 
-    p_vout->pf_init = Init;
-    p_vout->pf_end = End;
-    p_vout->pf_manage = Manage;
-    p_vout->pf_render = Render;
-    p_vout->pf_display = Display;
+    /* TODO */
+    vout_display_info_t info = vd->info;
+
+    /* Setup vout_display now that everything is fine */
+    vd->fmt = fmt;
+    vd->info = info;
+
+    vd->get = Get;
+    vd->prepare = Prepare;
+    vd->display = Display;
+    vd->control = Control;
+    vd->manage = Manage;
+
+    /* Fix initial state */
+    vout_display_SendEventFullscreen(vd, false);
+    Refresh(vd);
 
     return VLC_SUCCESS;
+
+error:
+    if (sys) {
+        if (sys->pool)
+            picture_pool_Delete(sys->pool);
+        if (sys->dither)
+            cucul_free_dither(sys->dither);
+        if (sys->dp)
+            caca_free_display(sys->dp);
+        if (sys->cv)
+            cucul_free_canvas(sys->cv);
+
+        free(sys);
+    }
+#if defined(WIN32) && !defined(UNDER_CE)
+    FreeConsole();
+#endif
+    return VLC_EGENERIC;
 }
 
-/*****************************************************************************
- * Init: initialize libcaca video output thread
- *****************************************************************************/
-static int Init( vout_thread_t *p_vout )
+/**
+ * Close a libcaca video output
+ */
+static void Close(vlc_object_t *object)
 {
-    int i_index;
-    picture_t *p_pic = NULL;
-
-    I_OUTPUTPICTURES = 0;
-
-    p_vout->output.i_chroma = VLC_CODEC_RGB32;
-    p_vout->output.i_width = p_vout->render.i_width;
-    p_vout->output.i_height = p_vout->render.i_height;
-    p_vout->output.i_aspect = p_vout->render.i_aspect;
-
-    p_vout->output.i_rmask = 0x00ff0000;
-    p_vout->output.i_gmask = 0x0000ff00;
-    p_vout->output.i_bmask = 0x000000ff;
-
-    /* Create the libcaca dither object */
-    p_vout->p_sys->p_dither = cucul_create_dither
-                       ( 32, p_vout->output.i_width, p_vout->output.i_height,
-                         4 * ((p_vout->output.i_width + 15) & ~15),
-                         p_vout->output.i_rmask, p_vout->output.i_gmask,
-                         p_vout->output.i_bmask, 0x00000000 );
-
-    if( !p_vout->p_sys->p_dither )
-    {
-        msg_Err( p_vout, "could not create libcaca dither object" );
-        return VLC_EGENERIC;
-    }
+    vout_display_t *vd = (vout_display_t *)object;
+    vout_display_sys_t *sys = vd->sys;
 
-    /* Find an empty picture slot */
-    for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
-    {
-        if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
-        {
-            p_pic = p_vout->p_picture + i_index;
-            break;
-        }
-    }
+    picture_pool_Delete(sys->pool);
+    if (sys->dither)
+        cucul_free_dither(sys->dither);
+    caca_free_display(sys->dp);
+    cucul_free_canvas(sys->cv);
 
-    if( p_pic == NULL )
-    {
-        return VLC_EGENERIC;
+#if defined(WIN32) && !defined(UNDER_CE)
+    FreeConsole();
+#endif
+
+    free(sys);
+}
+
+/**
+ * Return a direct buffer
+ */
+static picture_t *Get(vout_display_t *vd)
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    return picture_pool_Get(sys->pool);
+}
+
+/**
+ * Prepare a picture for display */
+static void Prepare(vout_display_t *vd, picture_t *picture)
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    if (!sys->dither) {
+        /* Create the libcaca dither object */
+        sys->dither = cucul_create_dither(32,
+                                            vd->source.i_visible_width,
+                                            vd->source.i_visible_height,
+                                            picture->p[0].i_pitch,
+                                            vd->fmt.i_rmask,
+                                            vd->fmt.i_gmask,
+                                            vd->fmt.i_bmask,
+                                            0x00000000);
+
+        if (!sys->dither) {
+            msg_Err(vd, "could not create libcaca dither object");
+            return;
+        }
     }
 
-    /* Allocate the picture */
-    p_pic->p->i_lines = p_vout->output.i_height;
-    p_pic->p->i_visible_lines = p_vout->output.i_height;
-    p_pic->p->i_pitch = 4 * ((p_vout->output.i_width + 15) & ~15);
-    p_pic->p->i_pixel_pitch = 4;
-    p_pic->p->i_visible_pitch = 4 * p_vout->output.i_width;
-    p_pic->i_planes = 1;
-    p_pic->p->p_pixels = malloc( p_pic->p->i_pitch * p_pic->p->i_lines );
+    vout_display_place_t place;
+    Place(vd, &place);
 
-    p_pic->i_status = DESTROYED_PICTURE;
-    p_pic->i_type   = DIRECT_PICTURE;
+    cucul_set_color_ansi(sys->cv, CUCUL_COLOR_DEFAULT, CUCUL_COLOR_BLACK);
+    cucul_clear_canvas(sys->cv);
 
-    PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
-    I_OUTPUTPICTURES++;
+    const int crop_offset = vd->source.i_y_offset * picture->p->i_pitch +
+                            vd->source.i_x_offset * picture->p->i_pixel_pitch;
+    cucul_dither_bitmap(sys->cv, place.x, place.y,
+                        place.width, place.height,
+                        sys->dither,
+                        &picture->p->p_pixels[crop_offset]);
+}
 
-    return VLC_SUCCESS;
+/**
+ * Display a picture
+ */
+static void Display(vout_display_t *vd, picture_t *picture)
+{
+    Refresh(vd);
+    picture_Release(picture);
 }
 
-/*****************************************************************************
- * End: terminate libcaca video output thread
- *****************************************************************************/
-static void End( vout_thread_t *p_vout )
+/**
+ * Control for vout display
+ */
+static int Control(vout_display_t *vd, int query, va_list args)
 {
-    cucul_free_dither( p_vout->p_sys->p_dither );
+    vout_display_sys_t *sys = vd->sys;
+
+    switch (query) {
+    case VOUT_DISPLAY_HIDE_MOUSE:
+        caca_set_mouse(sys->dp, 0);
+        return VLC_SUCCESS;
+
+    case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: {
+        const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t *);
+
+        caca_refresh_display(sys->dp);
+
+        /* Not quite good but not sure how to resize it */
+        if (cfg->display.width  != caca_get_display_width(sys->dp) ||
+            cfg->display.height != caca_get_display_height(sys->dp))
+            return VLC_EGENERIC;
+        return VLC_SUCCESS;
+    }
+
+    case VOUT_DISPLAY_CHANGE_ZOOM:
+    case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
+    case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
+        return VLC_SUCCESS;
+
+    case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
+        if (sys->dither)
+            cucul_free_dither(sys->dither);
+        sys->dither = NULL;
+        return VLC_SUCCESS;
+
+    default:
+        msg_Err(vd, "Unsupported query in vout display caca");
+        return VLC_EGENERIC;
+    }
 }
 
-/*****************************************************************************
- * Destroy: destroy libcaca video output thread
- *****************************************************************************
- * Terminate an output method created by AaCreateOutputMethod
- *****************************************************************************/
-static void Destroy( vlc_object_t *p_this )
+/**
+ * Refresh the display and send resize event
+ */
+static void Refresh(vout_display_t *vd)
 {
-    vout_thread_t *p_vout = (vout_thread_t *)p_this;
+    vout_display_sys_t *sys = vd->sys;
 
-    caca_free_display( p_vout->p_sys->p_dp );
-    cucul_free_canvas( p_vout->p_sys->p_cv );
+    /* */
+    caca_refresh_display(sys->dp);
 
-#if defined( WIN32 ) && !defined( UNDER_CE )
-    FreeConsole();
-#endif
+    /* */
+    const int width  = caca_get_display_width(sys->dp);
+    const int height = caca_get_display_height(sys->dp);
 
-    free( p_vout->p_sys );
+    if (width  != vd->cfg->display.width ||
+        height != vd->cfg->display.height)
+        vout_display_SendEventDisplaySize(vd, width, height);
 }
 
-/*****************************************************************************
- * Manage: handle libcaca events
- *****************************************************************************
- * This function should be called regularly by video output thread. It manages
- * console events. It returns a non null value on error.
- *****************************************************************************/
-static int Manage( vout_thread_t *p_vout )
+/**
+ * Compute the place in canvas unit.
+ */
+static void Place(vout_display_t *vd, vout_display_place_t *place)
 {
-#ifdef CACA_API_VERSION_1
-    struct caca_event ev;
-#else
-    int ev;
-#endif
+    vout_display_sys_t *sys = vd->sys;
+
+    vout_display_PlacePicture(place, &vd->source, vd->cfg, false);
+
+    const int canvas_width   = cucul_get_canvas_width(sys->cv);
+    const int canvas_height  = cucul_get_canvas_height(sys->cv);
+    const int display_width  = caca_get_display_width(sys->dp);
+    const int display_height = caca_get_display_height(sys->dp);
+
+    if (display_width > 0 && display_height > 0) {
+        place->x      =  place->x      * canvas_width  / display_width;
+        place->y      =  place->y      * canvas_height / display_height;
+        place->width  = (place->width  * canvas_width  + display_width/2)  / display_width;
+        place->height = (place->height * canvas_height + display_height/2) / display_height;
+    } else {
+        place->x = 0;
+        place->y = 0;
+        place->width  = canvas_width;
+        place->height = display_height;
+    }
+}
 
-    while( caca_get_event(p_vout->p_sys->p_dp, CACA_EVENT_ANY, &ev, 0) )
-    {
-        playlist_t *p_playlist;
-        vlc_value_t val;
-
-#ifdef CACA_API_VERSION_1
-#ifdef CACA_EVENT_OPAQUE
-        switch( caca_get_event_type( &ev ) )
-#else
-        switch( ev.type )
-#endif /* CACA_EVENT_OPAQUE */
-#else
-        switch( ev )
-#endif
-        {
-        case CACA_EVENT_KEY_RELEASE:
-#ifdef CACA_API_VERSION_1
-#ifdef CACA_EVENT_OPAQUE
-            switch( caca_get_event_key_ch( &ev ) )
-#else
-            switch( ev.data.key.ch )
-#endif /* CACA_EVENT_OPAQUE */
-#else
-            switch( ev & 0x00ffffff )
-#endif
-            {
-            case 'q':
-                val.i_int = KEY_MODIFIER_CTRL | 'q';
-                break;
-            case ' ':
-                val.i_int = KEY_SPACE;
-                break;
-            default:
-                continue;
-            }
+/* */
+static const struct {
+    int caca;
+    int vlc;
+} keys[] = {
+
+    { CACA_KEY_CTRL_A,  KEY_MODIFIER_CTRL | 'a' },
+    { CACA_KEY_CTRL_B,  KEY_MODIFIER_CTRL | 'b' },
+    { CACA_KEY_CTRL_C,  KEY_MODIFIER_CTRL | 'c' },
+    { CACA_KEY_CTRL_D,  KEY_MODIFIER_CTRL | 'd' },
+    { CACA_KEY_CTRL_E,  KEY_MODIFIER_CTRL | 'e' },
+    { CACA_KEY_CTRL_F,  KEY_MODIFIER_CTRL | 'f' },
+    { CACA_KEY_CTRL_G,  KEY_MODIFIER_CTRL | 'g' },
+    { CACA_KEY_BACKSPACE, KEY_BACKSPACE },
+    { CACA_KEY_TAB,     KEY_TAB },
+    { CACA_KEY_CTRL_J,  KEY_MODIFIER_CTRL | 'j' },
+    { CACA_KEY_CTRL_K,  KEY_MODIFIER_CTRL | 'k' },
+    { CACA_KEY_CTRL_L,  KEY_MODIFIER_CTRL | 'l' },
+    { CACA_KEY_RETURN,  KEY_ENTER },
+
+    { CACA_KEY_CTRL_N,  KEY_MODIFIER_CTRL | 'n' },
+    { CACA_KEY_CTRL_O,  KEY_MODIFIER_CTRL | 'o' },
+    { CACA_KEY_CTRL_P,  KEY_MODIFIER_CTRL | 'p' },
+    { CACA_KEY_CTRL_Q,  KEY_MODIFIER_CTRL | 'q' },
+    { CACA_KEY_CTRL_R,  KEY_MODIFIER_CTRL | 'r' },
+
+    { CACA_KEY_PAUSE,   -1 },
+    { CACA_KEY_CTRL_T,  KEY_MODIFIER_CTRL | 't' },
+    { CACA_KEY_CTRL_U,  KEY_MODIFIER_CTRL | 'u' },
+    { CACA_KEY_CTRL_V,  KEY_MODIFIER_CTRL | 'v' },
+    { CACA_KEY_CTRL_W,  KEY_MODIFIER_CTRL | 'w' },
+    { CACA_KEY_CTRL_X,  KEY_MODIFIER_CTRL | 'x' },
+    { CACA_KEY_CTRL_Y,  KEY_MODIFIER_CTRL | 'y' },
+    { CACA_KEY_CTRL_Z,  KEY_MODIFIER_CTRL | 'z' },
+
+    { CACA_KEY_ESCAPE,  KEY_ESC },
+    { CACA_KEY_DELETE,  KEY_DELETE },
+
+    { CACA_KEY_F1,      KEY_F1 },
+    { CACA_KEY_F2,      KEY_F2 },
+    { CACA_KEY_F3,      KEY_F3 },
+    { CACA_KEY_F4,      KEY_F4 },
+    { CACA_KEY_F5,      KEY_F5 },
+    { CACA_KEY_F6,      KEY_F6 },
+    { CACA_KEY_F7,      KEY_F7 },
+    { CACA_KEY_F8,      KEY_F8 },
+    { CACA_KEY_F9,      KEY_F9 },
+    { CACA_KEY_F10,     KEY_F10 },
+    { CACA_KEY_F11,     KEY_F11 },
+    { CACA_KEY_F12,     KEY_F12 },
+    { CACA_KEY_F13,     -1 },
+    { CACA_KEY_F14,     -1 },
+    { CACA_KEY_F15,     -1 },
+
+    { CACA_KEY_UP,      KEY_UP },
+    { CACA_KEY_DOWN,    KEY_DOWN },
+    { CACA_KEY_LEFT,    KEY_LEFT },
+    { CACA_KEY_RIGHT,   KEY_RIGHT },
+
+    { CACA_KEY_INSERT,  KEY_INSERT },
+    { CACA_KEY_HOME,    KEY_HOME },
+    { CACA_KEY_END,     KEY_END },
+    { CACA_KEY_PAGEUP,  KEY_PAGEUP },
+    { CACA_KEY_PAGEDOWN,KEY_PAGEDOWN },
+
+    { ' ',              KEY_SPACE },
+
+    /* */
+    { -1, -1 }
+};
+
+static const struct {
+    int caca;
+    int vlc;
+} mouses[] = {
+    { 1, MOUSE_BUTTON_LEFT },
+    { 2, MOUSE_BUTTON_CENTER },
+    { 3, MOUSE_BUTTON_RIGHT },
+    { 4, MOUSE_BUTTON_WHEEL_UP },
+    { 5, MOUSE_BUTTON_WHEEL_DOWN },
+
+    /* */
+    { -1, -1 }
+};
+
+/**
+ * Proccess pending event
+ */
+static void Manage(vout_display_t *vd)
+{
+    vout_display_sys_t *sys = vd->sys;
 
-            var_Set( p_vout->p_libvlc, "key-pressed", val );
+    struct caca_event ev;
+    while (caca_get_event(sys->dp, CACA_EVENT_ANY, &ev, 0) > 0) {
+        switch (caca_get_event_type(&ev)) {
+        case CACA_EVENT_KEY_PRESS: {
+            const int caca = caca_get_event_key_ch(&ev);
+
+            for (int i = 0; keys[i].caca != -1; i++) {
+                if (keys[i].caca == caca) {
+                    const int vlc = keys[i].vlc;
+
+                    if (vlc >= 0)
+                        vout_display_SendEventKey(vd, vlc);
+                    return;
+                }
+            }
+            if (caca >= 0x20 && caca <= 0x7f) {
+                vout_display_SendEventKey(vd, caca);
+                return;
+            }
             break;
+        }
         case CACA_EVENT_RESIZE:
-            /* Acknowledge the resize */
-            caca_refresh_display( p_vout->p_sys->p_dp );
+            vout_display_SendEventDisplaySize(vd, caca_get_event_resize_width(&ev),
+                                                  caca_get_event_resize_height(&ev));
             break;
-#ifdef CACA_API_VERSION_1
-        case  CACA_EVENT_MOUSE_MOTION:
-            val.i_int =
-#ifdef CACA_EVENT_OPAQUE
-                caca_get_event_mouse_x( &ev )
-#else
-                ev.data.mouse.x
-#endif /* CACA_EVENT_OPAQUE */
-                * p_vout->render.i_width
-                         / cucul_get_canvas_width( p_vout->p_sys->p_cv );
-            var_Set( p_vout, "mouse-x", val );
-            val.i_int =
-#ifdef CACA_EVENT_OPAQUE
-                caca_get_event_mouse_y( &ev ) 
-#else
-                ev.data.mouse.y
-#endif /* CACA_EVENT_OPAQUE */
-                * p_vout->render.i_height
-                         / cucul_get_canvas_height( p_vout->p_sys->p_cv );
-            var_Set( p_vout, "mouse-y", val );
-            var_SetBool( p_vout, "mouse-moved", true );
-            break;
-        case CACA_EVENT_MOUSE_RELEASE:
-            var_SetBool( p_vout, "mouse-clicked", true );
+        case CACA_EVENT_MOUSE_MOTION: {
+            vout_display_place_t place;
+            Place(vd, &place);
+
+            const unsigned x = vd->source.i_x_offset +
+                               (int64_t)(caca_get_event_mouse_x(&ev) - place.x) *
+                                    vd->source.i_visible_width / place.width;
+            const unsigned y = vd->source.i_y_offset +
+                               (int64_t)(caca_get_event_mouse_y(&ev) - place.y) *
+                                    vd->source.i_visible_height / place.height;
+
+            caca_set_mouse(sys->dp, 1);
+            if (x >= vd->source.i_x_offset && x < vd->source.i_x_offset + vd->source.i_visible_width &&
+                y >= vd->source.i_y_offset && y < vd->source.i_y_offset + vd->source.i_visible_height) {
+                vout_display_SendEventMouseMoved(vd, x, y);
+            }
             break;
-        case CACA_EVENT_QUIT:
-        {
-            p_playlist = pl_Hold( p_vout );
-            if( p_playlist )
-            {
-                playlist_Stop( p_playlist );
-                pl_Release( p_vout );
+        }
+        case CACA_EVENT_MOUSE_PRESS:
+        case CACA_EVENT_MOUSE_RELEASE: {
+            caca_set_mouse(sys->dp, 1);
+            const int caca = caca_get_event_mouse_button(&ev);
+            for (int i = 0; mouses[i].caca != -1; i++) {
+                if (mouses[i].caca == caca) {
+                    if (caca_get_event_type(&ev) == CACA_EVENT_MOUSE_PRESS)
+                        vout_display_SendEventMousePressed(vd, mouses[i].vlc);
+                    else
+                        vout_display_SendEventMouseReleased(vd, mouses[i].vlc);
+                    return;
+                }
             }
-            libvlc_Quit( p_vout->p_libvlc );
             break;
         }
-#endif
+        case CACA_EVENT_QUIT:
+            vout_display_SendEventClose(vd);
+            break;
         default:
             break;
         }
     }
-
-    return VLC_SUCCESS;
-}
-
-/*****************************************************************************
- * Render: render previously calculated output
- *****************************************************************************/
-static void Render( vout_thread_t *p_vout, picture_t *p_pic )
-{
-    cucul_set_color_ansi( p_vout->p_sys->p_cv,
-                     CUCUL_COLOR_DEFAULT, CUCUL_COLOR_BLACK );
-    cucul_clear_canvas( p_vout->p_sys->p_cv );
-    cucul_dither_bitmap( p_vout->p_sys->p_cv, 0, 0,
-                         cucul_get_canvas_width( p_vout->p_sys->p_cv ) - 1,
-                         cucul_get_canvas_height( p_vout->p_sys->p_cv ) - 1,
-                         p_vout->p_sys->p_dither, p_pic->p->p_pixels );
-}
-
-/*****************************************************************************
- * Display: displays previously rendered output
- *****************************************************************************/
-static void Display( vout_thread_t *p_vout, picture_t *p_pic )
-{
-    VLC_UNUSED(p_pic);
-    caca_refresh_display( p_vout->p_sys->p_dp );
 }