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