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