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