mkv: abort if read fails during seek
[vlc.git] / modules / video_output / sdl.c
1 /*****************************************************************************
2  * sdl.c: SDL video output display method
3  *****************************************************************************
4  * Copyright (C) 1998-2009 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          Pierre Baillet <oct@zoy.org>
9  *          Arnaud de Bossoreille de Ribou <bozo@via.ecp.fr>
10  *          Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
11  *
12  * This program is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU Lesser General Public License as published by
14  * the Free Software Foundation; either version 2.1 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public License
23  * along with this program; if not, write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_vout_display.h>
37 #include <vlc_picture_pool.h>
38
39 #include <assert.h>
40
41 #include <SDL.h>
42
43 #if !defined(_WIN32) && !defined(__OS2__)
44 # ifdef X_DISPLAY_MISSING
45 #  error Xlib required due to XInitThreads
46 # endif
47 # include <vlc_xlib.h>
48 #endif
49
50 /*****************************************************************************
51  * Module descriptor
52  *****************************************************************************/
53 static int  Open (vlc_object_t *);
54 static void Close(vlc_object_t *);
55
56 #define CHROMA_TEXT N_("SDL chroma format")
57 #define CHROMA_LONGTEXT N_(\
58     "Force the SDL renderer to use a specific chroma format instead of " \
59     "trying to improve performances by using the most efficient one.")
60
61 #define OVERLAY_TEXT N_("YUV overlay")
62 #define OVERLAY_LONGTEXT N_(\
63     "Use the hardware YUV overlay of the graphic card (if available).")
64
65 vlc_module_begin()
66     set_shortname("SDL")
67     set_category(CAT_VIDEO)
68     set_subcategory(SUBCAT_VIDEO_VOUT)
69     set_description(N_("Simple DirectMedia Layer video output"))
70     set_capability("vout display", 70)
71     add_shortcut("sdl")
72     add_bool("sdl-overlay", true, OVERLAY_TEXT, OVERLAY_LONGTEXT, false)
73     add_string("sdl-chroma", NULL, CHROMA_TEXT, CHROMA_LONGTEXT, true)
74     add_obsolete_string("sdl-video-driver") /* obsolete since 1.1.0 */
75     set_callbacks(Open, Close)
76 #if defined(__i386__) || defined(__x86_64__)
77     /* On i386, SDL is linked against svgalib */
78     cannot_unload_broken_library()
79 #endif
80 vlc_module_end()
81
82
83 /*****************************************************************************
84  * Local prototypes
85  *****************************************************************************/
86 static picture_pool_t *Pool  (vout_display_t *, unsigned);
87 static void           PictureDisplay(vout_display_t *, picture_t *, subpicture_t *);
88 static int            Control(vout_display_t *, int, va_list);
89 static void           Manage(vout_display_t *);
90
91 /* */
92 static int ConvertKey(SDLKey);
93
94 /* */
95 static vlc_mutex_t sdl_lock = VLC_STATIC_MUTEX;
96
97 /* */
98 struct vout_display_sys_t {
99     vout_display_place_t place;
100
101     SDL_Surface          *display;
102     int                  display_bpp;
103     uint32_t             display_flags;
104
105     unsigned int         desktop_width;
106     unsigned int         desktop_height;
107
108     /* For YUV output */
109     SDL_Overlay          *overlay;
110     bool                 is_uv_swapped;
111
112     /* */
113     picture_pool_t       *pool;
114 };
115
116 /**
117  * This function initializes SDL vout method.
118  */
119 static int Open(vlc_object_t *object)
120 {
121     vout_display_t *vd = (vout_display_t *)object;
122     vout_display_sys_t *sys;
123
124     if (vout_display_IsWindowed(vd))
125         return VLC_EGENERIC;
126 #if !defined(_WIN32) && !defined(__OS2__)
127     if (!vlc_xlib_init (object))
128         return VLC_EGENERIC;
129 #endif
130
131     /* XXX: check for conflicts with the SDL audio output */
132     vlc_mutex_lock(&sdl_lock);
133
134     /* Check if SDL video module has been initialized */
135     if (SDL_WasInit(SDL_INIT_VIDEO) != 0) {
136         vlc_mutex_unlock(&sdl_lock);
137         return VLC_EGENERIC;
138     }
139
140     vd->sys = sys = calloc(1, sizeof(*sys));
141     if (!sys) {
142         vlc_mutex_unlock(&sdl_lock);
143         return VLC_ENOMEM;
144     }
145
146     /* */
147     int sdl_flags = SDL_INIT_VIDEO;
148 #ifndef _WIN32
149     /* Win32 SDL implementation doesn't support SDL_INIT_EVENTTHREAD yet*/
150     sdl_flags |= SDL_INIT_EVENTTHREAD;
151 #endif
152     /* In debug mode you may want vlc to dump a core instead of staying stuck */
153     sdl_flags |= SDL_INIT_NOPARACHUTE;
154
155     /* Initialize library */
156     if (SDL_Init(sdl_flags) < 0) {
157         vlc_mutex_unlock(&sdl_lock);
158
159         msg_Err(vd, "cannot initialize SDL (%s)", SDL_GetError());
160         free(sys);
161         return VLC_EGENERIC;
162     }
163     vlc_mutex_unlock(&sdl_lock);
164
165     /* Translate keys into unicode */
166     SDL_EnableUNICODE(1);
167
168     /* Get the desktop resolution */
169     /* FIXME: SDL has a problem with virtual desktop */
170     sys->desktop_width  = SDL_GetVideoInfo()->current_w;
171     sys->desktop_height = SDL_GetVideoInfo()->current_h;
172
173     /* */
174     video_format_t fmt;
175     video_format_ApplyRotation(&fmt, &vd->fmt);
176
177     /* */
178     vout_display_info_t info = vd->info;
179
180     /* Set main window's size */
181     int display_width;
182     int display_height;
183     if (vd->cfg->is_fullscreen) {
184         display_width  = sys->desktop_width;
185         display_height = sys->desktop_height;
186     } else {
187         display_width  = vd->cfg->display.width;
188         display_height = vd->cfg->display.height;
189     }
190
191     /* Initialize flags and cursor */
192     sys->display_flags = SDL_ANYFORMAT | SDL_HWPALETTE | SDL_HWSURFACE | SDL_DOUBLEBUF;
193     sys->display_flags |= vd->cfg->is_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE;
194
195     sys->display_bpp = SDL_VideoModeOK(display_width, display_height,
196                                        16, sys->display_flags);
197     if (sys->display_bpp == 0) {
198         msg_Err(vd, "no video mode available");
199         goto error;
200     }
201
202     sys->display = SDL_SetVideoMode(display_width, display_height,
203                                     sys->display_bpp, sys->display_flags);
204     if (!sys->display) {
205         msg_Err(vd, "cannot set video mode");
206         goto error;
207     }
208
209     /* We keep the surface locked forever */
210     SDL_LockSurface(sys->display);
211
212     /* */
213     vlc_fourcc_t forced_chroma = 0;
214     char *psz_chroma = var_InheritString(vd, "sdl-chroma");
215     if (psz_chroma) {
216         forced_chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, psz_chroma);
217         if (forced_chroma)
218             msg_Dbg(vd, "Forcing chroma to 0x%.8x (%4.4s)",
219                     forced_chroma, (const char*)&forced_chroma);
220         free(psz_chroma);
221     }
222
223     /* Try to open an overlay if requested */
224     sys->overlay = NULL;
225     const bool is_overlay = var_InheritBool(vd, "sdl-overlay");
226     if (is_overlay) {
227         static const struct
228         {
229             vlc_fourcc_t vlc;
230             uint32_t     sdl;
231         } vlc_to_sdl[] = {
232             { VLC_CODEC_YV12, SDL_YV12_OVERLAY },
233             { VLC_CODEC_I420, SDL_IYUV_OVERLAY },
234             { VLC_CODEC_YUYV, SDL_YUY2_OVERLAY },
235             { VLC_CODEC_UYVY, SDL_UYVY_OVERLAY },
236             { VLC_CODEC_YVYU, SDL_YVYU_OVERLAY },
237
238             { 0, 0 }
239         };
240         const vlc_fourcc_t forced_chromas[] = {
241             forced_chroma, 0
242         };
243         const vlc_fourcc_t *fallback_chromas =
244             vlc_fourcc_GetYUVFallback(fmt.i_chroma);
245         const vlc_fourcc_t *chromas = forced_chroma ? forced_chromas : fallback_chromas;
246
247         for (int pass = forced_chroma ? 1 : 0; pass < 2 && !sys->overlay; pass++) {
248             for (int i = 0; chromas[i] != 0; i++) {
249                 const vlc_fourcc_t vlc = chromas[i];
250
251                 uint32_t sdl = 0;
252                 for (int j = 0; vlc_to_sdl[j].vlc != 0 && !sdl; j++) {
253                     if (vlc_to_sdl[j].vlc == vlc)
254                         sdl = vlc_to_sdl[j].sdl;
255                 }
256                 if (!sdl)
257                     continue;
258
259                 sys->overlay = SDL_CreateYUVOverlay(fmt.i_width, fmt.i_height,
260                                                     sdl, sys->display);
261                 if (sys->overlay && !sys->overlay->hw_overlay && pass == 0) {
262                     /* Ignore non hardware overlay surface in first pass */
263                     SDL_FreeYUVOverlay(sys->overlay);
264                     sys->overlay = NULL;
265                 }
266                 if (sys->overlay) {
267                     /* We keep the surface locked forever */
268                     SDL_LockYUVOverlay(sys->overlay);
269
270                     fmt.i_chroma = vlc;
271                     sys->is_uv_swapped = vlc_fourcc_AreUVPlanesSwapped(fmt.i_chroma,
272                                                                        vd->fmt.i_chroma);
273                     if (sys->is_uv_swapped)
274                         fmt.i_chroma = vd->fmt.i_chroma;
275                     break;
276                 }
277             }
278         }
279     } else {
280         msg_Warn(vd, "SDL overlay disabled by the user");
281     }
282
283     /* */
284     vout_display_cfg_t place_cfg = *vd->cfg;
285     place_cfg.display.width  = display_width;
286     place_cfg.display.height = display_height;
287     vout_display_PlacePicture(&sys->place, &vd->source, &place_cfg, !sys->overlay);
288
289     /* If no overlay, fallback to software output */
290     if (!sys->overlay) {
291         /* */
292         switch (sys->display->format->BitsPerPixel) {
293         case 8:
294             fmt.i_chroma = VLC_CODEC_RGB8;
295             break;
296         case 15:
297             fmt.i_chroma = VLC_CODEC_RGB15;
298             break;
299         case 16:
300             fmt.i_chroma = VLC_CODEC_RGB16;
301             break;
302         case 24:
303             fmt.i_chroma = VLC_CODEC_RGB24;
304             break;
305         case 32:
306             fmt.i_chroma = VLC_CODEC_RGB32;
307             break;
308         default:
309             msg_Err(vd, "unknown screen depth %i",
310                     sys->display->format->BitsPerPixel);
311             goto error;
312         }
313
314         /* All we have is an RGB image with square pixels */
315         fmt.i_width  = display_width;
316         fmt.i_height = display_height;
317         fmt.i_rmask = sys->display->format->Rmask;
318         fmt.i_gmask = sys->display->format->Gmask;
319         fmt.i_bmask = sys->display->format->Bmask;
320
321         info.has_pictures_invalid = true;
322     }
323
324     if (vd->cfg->display.title)
325         SDL_WM_SetCaption(vd->cfg->display.title,
326                           vd->cfg->display.title);
327     else if (!sys->overlay)
328         SDL_WM_SetCaption(VOUT_TITLE " (software RGB SDL output)",
329                           VOUT_TITLE " (software RGB SDL output)");
330     else if (sys->overlay->hw_overlay)
331         SDL_WM_SetCaption(VOUT_TITLE " (hardware YUV SDL output)",
332                           VOUT_TITLE " (hardware YUV SDL output)");
333     else
334         SDL_WM_SetCaption(VOUT_TITLE " (software YUV SDL output)",
335                           VOUT_TITLE " (software YUV SDL output)");
336
337     /* Setup events */
338     SDL_EventState(SDL_KEYUP, SDL_IGNORE);               /* ignore keys up */
339
340     /* Setup vout_display now that everything is fine */
341     vd->fmt = fmt;
342     vd->info = info;
343
344     vd->pool    = Pool;
345     vd->prepare = NULL;
346     vd->display = PictureDisplay;
347     vd->control = Control;
348     vd->manage  = Manage;
349
350     /* */
351     vout_display_SendEventDisplaySize(vd, display_width, display_height);
352     return VLC_SUCCESS;
353
354 error:
355     msg_Err(vd, "cannot set up SDL (%s)", SDL_GetError());
356
357     if (sys->display) {
358         SDL_UnlockSurface(sys->display);
359         SDL_FreeSurface(sys->display);
360     }
361
362     vlc_mutex_lock(&sdl_lock);
363     SDL_QuitSubSystem(SDL_INIT_VIDEO);
364     vlc_mutex_unlock(&sdl_lock);
365
366     free(sys);
367     return VLC_EGENERIC;
368 }
369
370 /**
371  * Close a SDL video output
372  */
373 static void Close(vlc_object_t *object)
374 {
375     vout_display_t *vd = (vout_display_t *)object;
376     vout_display_sys_t *sys = vd->sys;
377
378     if (sys->pool)
379         picture_pool_Release(sys->pool);
380
381     if (sys->overlay) {
382         SDL_LockYUVOverlay(sys->overlay);
383         SDL_FreeYUVOverlay(sys->overlay);
384     }
385     SDL_UnlockSurface (sys->display);
386     SDL_FreeSurface(sys->display);
387
388     vlc_mutex_lock(&sdl_lock);
389     SDL_QuitSubSystem(SDL_INIT_VIDEO);
390     vlc_mutex_unlock(&sdl_lock);
391
392     free(sys);
393 }
394
395 /**
396  * Return a pool of direct buffers
397  */
398 static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
399 {
400     vout_display_sys_t *sys = vd->sys;
401     VLC_UNUSED(count);
402
403     if (!sys->pool) {
404         picture_resource_t rsc;
405
406         memset(&rsc, 0, sizeof(rsc));
407
408         if (sys->overlay) {
409             SDL_Overlay *ol = sys->overlay;
410
411             for (int i = 0; i < ol->planes; i++) {
412                 rsc.p[i].p_pixels = ol->pixels[ i > 0 && sys->is_uv_swapped ? (3-i) : i];
413                 rsc.p[i].i_pitch  = ol->pitches[i > 0 && sys->is_uv_swapped ? (3-i) : i];
414                 rsc.p[i].i_lines  = ol->h;
415                 if (ol->format == SDL_YV12_OVERLAY ||
416                     ol->format == SDL_IYUV_OVERLAY)
417                     rsc.p[i].i_lines /= 2;
418
419             }
420         } else {
421             const int x = sys->place.x;
422             const int y = sys->place.y;
423
424             SDL_Surface *sf = sys->display;
425             SDL_FillRect(sf, NULL, 0);
426
427             assert(x >= 0 && y >= 0);
428             rsc.p[0].p_pixels = (uint8_t*)sf->pixels + y * sf->pitch + x * ((sf->format->BitsPerPixel + 7) / 8);
429             rsc.p[0].i_pitch  = sf->pitch;
430             rsc.p[0].i_lines  = vd->fmt.i_height;
431         }
432
433         picture_t *picture = picture_NewFromResource(&vd->fmt, &rsc);;
434         if (!picture)
435             return NULL;
436
437         sys->pool = picture_pool_New(1, &picture);
438     }
439
440     return sys->pool;
441 }
442
443 /**
444  * Display a picture
445  */
446 static void PictureDisplay(vout_display_t *vd, picture_t *p_pic, subpicture_t *p_subpicture)
447 {
448     vout_display_sys_t *sys = vd->sys;
449
450     if (sys->overlay) {
451         SDL_Rect disp;
452         disp.x = sys->place.x;
453         disp.y = sys->place.y;
454         disp.w = sys->place.width;
455         disp.h = sys->place.height;
456
457         SDL_UnlockYUVOverlay(sys->overlay);
458         SDL_DisplayYUVOverlay(sys->overlay , &disp);
459         SDL_LockYUVOverlay(sys->overlay);
460     } else {
461         SDL_Flip(sys->display);
462     }
463
464     picture_Release(p_pic);
465     VLC_UNUSED(p_subpicture);
466 }
467
468
469 /**
470  * Control for vout display
471  */
472 static int Control(vout_display_t *vd, int query, va_list args)
473 {
474     vout_display_sys_t *sys = vd->sys;
475
476     switch (query)
477     {
478     case VOUT_DISPLAY_HIDE_MOUSE:
479         SDL_ShowCursor(0);
480         return VLC_SUCCESS;
481
482     case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: {
483         const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t *);
484
485         /* */
486         sys->display = SDL_SetVideoMode(cfg->display.width,
487                                         cfg->display.height,
488                                         sys->display_bpp, sys->display_flags);
489         if (!sys->display) {
490             sys->display = SDL_SetVideoMode(vd->cfg->display.width,
491                                             vd->cfg->display.height,
492                                             sys->display_bpp, sys->display_flags);
493             return VLC_EGENERIC;
494         }
495         if (sys->overlay)
496             vout_display_PlacePicture(&sys->place, &vd->source, cfg, !sys->overlay);
497         else
498             vout_display_SendEventPicturesInvalid(vd);
499         return VLC_SUCCESS;
500     }
501     case VOUT_DISPLAY_CHANGE_FULLSCREEN: {
502         bool fs = va_arg(args, int);
503
504         /* Fix flags */
505         sys->display_flags &= ~(SDL_FULLSCREEN | SDL_RESIZABLE);
506         sys->display_flags |= fs ? SDL_FULLSCREEN : SDL_RESIZABLE;
507
508         if (sys->overlay)
509             sys->display = SDL_SetVideoMode(sys->desktop_width, sys->desktop_height,
510                                             sys->display_bpp, sys->display_flags);
511
512         vout_display_SendEventDisplaySize(vd, sys->desktop_width, sys->desktop_height);
513         return VLC_SUCCESS;
514     }
515     case VOUT_DISPLAY_CHANGE_ZOOM:
516     case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
517     case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT: {
518         const vout_display_cfg_t *cfg;
519         const video_format_t *source;
520
521         if (query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT) {
522             source = va_arg(args, const video_format_t *);
523             cfg = vd->cfg;
524         } else {
525             source = &vd->source;
526             cfg = va_arg(args, const vout_display_cfg_t *);
527         }
528         if (sys->overlay) {
529             sys->display = SDL_SetVideoMode(cfg->display.width, cfg->display.height,
530                                             sys->display_bpp, sys->display_flags);
531
532             vout_display_PlacePicture(&sys->place, source, cfg, !sys->overlay);
533         } else {
534             vout_display_SendEventPicturesInvalid(vd);
535         }
536         return VLC_SUCCESS;
537     }
538
539     case VOUT_DISPLAY_RESET_PICTURES: {
540         /* */
541         assert(!sys->overlay);
542
543         /* */
544         if (sys->pool)
545             picture_pool_Release(sys->pool);
546         sys->pool = NULL;
547
548         vout_display_PlacePicture(&sys->place, &vd->source, vd->cfg, !sys->overlay);
549
550         /* */
551         vd->fmt.i_width  = sys->place.width;
552         vd->fmt.i_height = sys->place.height;
553         return VLC_SUCCESS;
554     }
555
556     case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
557     case VOUT_DISPLAY_CHANGE_WINDOW_STATE:
558         /* I don't think it is possible to support with SDL:
559          * - crop
560          * - on top
561          */
562         return VLC_EGENERIC;
563
564     default:
565         msg_Err(vd, "Unsupported query in vout display SDL");
566         return VLC_EGENERIC;
567     }
568 }
569
570 /**
571  * Proccess pending event
572  */
573 static void Manage(vout_display_t *vd)
574 {
575     vout_display_sys_t *sys = vd->sys;
576     SDL_Event event;
577
578     /* */
579     while (SDL_PollEvent(&event)) {
580         switch (event.type) {
581         case SDL_QUIT:
582             vout_display_SendEventClose(vd);
583             break;
584
585         case SDL_KEYDOWN: {
586             /* convert the key if possible */
587             int key = ConvertKey(event.key.keysym.sym);
588
589             if (!key) {
590                 /* Find the right caracter */
591                 if ((event.key.keysym.unicode & 0xff80) == 0) {
592                     key = event.key.keysym.unicode & 0x7f;
593                     /* FIXME: find a better solution than this
594                               hack to find the right caracter */
595                     if (key >= 1 && key <= 26)
596                         key += 96;
597                     else if (key >= 65 && key <= 90)
598                         key += 32;
599                 }
600             }
601             if (!key)
602                 break;
603
604             if (event.key.keysym.mod & KMOD_SHIFT)
605                 key |= KEY_MODIFIER_SHIFT;
606             if (event.key.keysym.mod & KMOD_CTRL)
607                 key |= KEY_MODIFIER_CTRL;
608             if (event.key.keysym.mod & KMOD_ALT)
609                 key |= KEY_MODIFIER_ALT;
610             vout_display_SendEventKey(vd, key);
611             break;
612         }
613
614         case SDL_MOUSEBUTTONDOWN:
615         case SDL_MOUSEBUTTONUP: {
616             static const struct { int sdl; int vlc; } buttons[] = {
617                 { SDL_BUTTON_LEFT,      MOUSE_BUTTON_LEFT },
618                 { SDL_BUTTON_MIDDLE,    MOUSE_BUTTON_CENTER },
619                 { SDL_BUTTON_RIGHT,     MOUSE_BUTTON_RIGHT },
620                 { SDL_BUTTON_WHEELUP,   MOUSE_BUTTON_WHEEL_UP },
621                 { SDL_BUTTON_WHEELDOWN, MOUSE_BUTTON_WHEEL_DOWN },
622                 { -1, -1 },
623             };
624
625             SDL_ShowCursor(1);
626             for (int i = 0; buttons[i].sdl != -1; i++) {
627                 if (buttons[i].sdl == event.button.button) {
628                     if (event.type == SDL_MOUSEBUTTONDOWN)
629                         vout_display_SendEventMousePressed(vd, buttons[i].vlc);
630                     else
631                         vout_display_SendEventMouseReleased(vd, buttons[i].vlc);
632                 }
633             }
634             break;
635         }
636
637         case SDL_MOUSEMOTION: {
638             if (sys->place.width <= 0 || sys->place.height <= 0)
639                 break;
640
641             SDL_ShowCursor(1);
642
643             vout_display_SendMouseMovedDisplayCoordinates(vd, ORIENT_NORMAL,
644                                                           event.motion.x, event.motion.y,
645                                                           &sys->place);
646             break;
647         }
648
649         case SDL_VIDEORESIZE:
650             vout_display_SendEventDisplaySize(vd, event.resize.w, event.resize.h);
651             break;
652
653         default:
654             break;
655         }
656     }
657
658 }
659
660 static const struct {
661     SDLKey sdl_key;
662     int    vlckey;
663
664 } sdlkeys_to_vlckeys[] = {
665     { SDLK_F1,  KEY_F1 },
666     { SDLK_F2,  KEY_F2 },
667     { SDLK_F3,  KEY_F3 },
668     { SDLK_F4,  KEY_F4 },
669     { SDLK_F5,  KEY_F5 },
670     { SDLK_F6,  KEY_F6 },
671     { SDLK_F7,  KEY_F7 },
672     { SDLK_F8,  KEY_F8 },
673     { SDLK_F9,  KEY_F9 },
674     { SDLK_F10, KEY_F10 },
675     { SDLK_F11, KEY_F11 },
676     { SDLK_F12, KEY_F12 },
677
678     { SDLK_RETURN, KEY_ENTER },
679     { SDLK_KP_ENTER, KEY_ENTER },
680     { SDLK_SPACE, ' ' },
681     { SDLK_ESCAPE, KEY_ESC },
682
683     { SDLK_MENU, KEY_MENU },
684     { SDLK_LEFT, KEY_LEFT },
685     { SDLK_RIGHT, KEY_RIGHT },
686     { SDLK_UP, KEY_UP },
687     { SDLK_DOWN, KEY_DOWN },
688
689     { SDLK_HOME, KEY_HOME },
690     { SDLK_END, KEY_END },
691     { SDLK_PAGEUP, KEY_PAGEUP },
692     { SDLK_PAGEDOWN,  KEY_PAGEDOWN },
693
694     { SDLK_INSERT, KEY_INSERT },
695     { SDLK_DELETE, KEY_DELETE },
696     /*TODO: find a equivalent for SDL 
697     { , KEY_MEDIA_NEXT_TRACK }
698     { , KEY_MEDIA_PREV_TRACK }
699     { , KEY_VOLUME_MUTE }
700     { , KEY_VOLUME_DOWN }
701     { , KEY_VOLUME_UP }
702     { , KEY_MEDIA_PLAY_PAUSE }
703     { , KEY_MEDIA_PLAY_PAUSE }*/
704
705     { 0, 0 }
706 };
707
708 static int ConvertKey(SDLKey sdl_key)
709 {
710     for (int i = 0; sdlkeys_to_vlckeys[i].sdl_key != 0; i++) {
711         if (sdlkeys_to_vlckeys[i].sdl_key == sdl_key)
712             return sdlkeys_to_vlckeys[i].vlckey;
713     }
714     return 0;
715 }
716