Search
lxdream.org :: lxdream/src/display.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/display.c
changeset 1244:6b54ef5ed413
prev1239:be3121267597
next1245:01e0020adf88
author nkeynes
date Tue Feb 28 18:22:52 2012 +1000 (12 years ago)
permissions -rw-r--r--
last change Add a GL-only video driver for android usage (since the Java code is
responsible for creating the context)
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * Generic support for keyboard and other input sources. The active display
     5  * driver is expected to deliver events here, where they're translated and
     6  * passed to the appropriate dreamcast controllers (if any).
     7  *
     8  * Copyright (c) 2005 Nathan Keynes.
     9  *
    10  * This program is free software; you can redistribute it and/or modify
    11  * it under the terms of the GNU General Public License as published by
    12  * the Free Software Foundation; either version 2 of the License, or
    13  * (at your option) any later version.
    14  *
    15  * This program is distributed in the hope that it will be useful,
    16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    18  * GNU General Public License for more details.
    19  */
    21 #include <stdint.h>
    22 #include <assert.h>
    23 #include "dream.h"
    24 #include "display.h"
    25 #include "pvr2/pvr2.h"
    27 display_driver_t display_driver_list[] = {
    28 #ifdef HAVE_GTK
    29         &display_gtk_driver,
    30 #else
    31 #ifdef HAVE_COCOA
    32         &display_osx_driver,
    33 #endif
    34 #endif
    35 #ifdef __ANDROID__
    36         &display_gl_driver,
    37 #endif
    38         &display_null_driver,
    39         NULL };
    41 /* Some explanation:
    42  *   The system has at least one "root" device representing the main display 
    43  * (which may be the null display). This device is part of the display_driver
    44  * and generates events with no input_driver. The root device has no id
    45  * as such (for the purposes of event names)
    46  *
    47  *   The system may also have one or more auxilliary devices which each have
    48  * an input_driver and an id (eg "JS0"). So the keysym "Return" is (de)coded by
    49  * the root device, and the keysym "JS0: Button0" is (de)coded by the JS0 input
    50  * device as "Button0".
    51  *
    52  *   For the moment, mice are handled specially, as they behave a little
    53  * differently from other devices (although this will probably change in the 
    54  * future.
    55  */
    58 typedef struct keymap_entry {
    59     input_key_callback_t callback;
    60     void *data;
    61     uint32_t value;
    62     lxdream_config_group_t group;
    63     struct keymap_entry *next; // allow chaining
    64 } *keymap_entry_t;
    66 typedef struct mouse_entry {
    67     gboolean relative;
    68     input_mouse_callback_t callback;
    69     void *data;
    70     const lxdream_config_group_t group;
    71     struct mouse_entry *next;
    72 } *mouse_entry_t;
    74 typedef struct input_driver_entry {
    75     input_driver_t driver;
    76     uint16_t entry_count;
    77     struct keymap_entry *keymap[0];
    78 } *input_driver_entry_t;
    81 #ifndef GL_RGBA8
    82 #define GL_RGBA8 GL_RGBA8_OES
    83 #endif
    85 #ifndef GL_RGB5
    86 #define GL_RGB5 GL_RGB565
    87 #endif
    89 #ifndef GL_BGR
    90 #define GL_BGR GL_BGRA
    91 #endif
    93 /**
    94  * Colour format information
    95  */
    96 struct colour_format colour_formats[] = {
    97         { GL_UNSIGNED_SHORT_1_5_5_5_REV, GL_BGRA, GL_RGB5_A1, 2 },
    98         { GL_UNSIGNED_SHORT_5_6_5, GL_RGB, GL_RGB5, 2 },
    99         { GL_UNSIGNED_SHORT_4_4_4_4_REV, GL_BGRA, GL_RGBA4, 2 },
   100         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* YUV decoded to ARGB8888 */
   101         { GL_UNSIGNED_BYTE, GL_BGR, GL_RGB, 3 },
   102         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 },
   103         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* Index4 decoded */
   104         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* Index8 decoded */
   105         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 },
   106         { GL_UNSIGNED_BYTE, GL_RGB, GL_RGB, 3 },
   108 };
   110 /**
   111  * FIXME: make this more memory efficient
   112  */
   113 static struct keymap_entry *root_keymap[65535];
   114 static struct keymap_entry *keyhooks = NULL;
   115 static gboolean display_focused = TRUE;
   116 static GList *input_drivers= NULL;
   117 static display_keysym_callback_t display_keysym_hook = NULL;
   118 void *display_keysym_hook_data;
   120 gboolean input_register_device( input_driver_t driver, uint16_t max_keycode )
   121 {
   122     GList *ptr;
   123     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   124         input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   125         if( strcasecmp( entry->driver->id, driver->id ) == 0 ) {
   126             return FALSE;
   127         }
   128     }
   130     input_driver_entry_t entry = g_malloc0( sizeof(struct input_driver_entry) + (sizeof(keymap_entry_t) * max_keycode) );
   131     entry->driver = driver;
   132     entry->entry_count = max_keycode;
   133     input_drivers = g_list_append( input_drivers, entry );
   134     return TRUE;
   135 }
   137 gboolean input_has_device( const gchar *id )
   138 {
   139     GList *ptr;
   140     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   141         input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   142         if( strcasecmp(entry->driver->id, id) == 0 ) {
   143             return TRUE;
   144         }
   145     }
   146     return FALSE;
   147 }
   150 void input_unregister_device( input_driver_t driver )
   151 {
   152     GList *ptr;
   153     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   154         input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   155         if( entry->driver == driver ) {
   156             if( driver->destroy != NULL ) {
   157                 driver->destroy(driver);
   158             }
   159             input_drivers = g_list_remove(input_drivers, (gpointer)entry);
   160             g_free( entry );
   161             return;
   162         }
   163     }
   164 }
   166 /**
   167  * Resolve the keysym and return a pointer to the keymap entry pointer
   168  * @return keymap pointer or NULL if the key was unresolved
   169  */
   170 static struct keymap_entry **input_entry_from_keysym( const gchar *keysym )
   171 {
   172     if( keysym == NULL || keysym[0] == 0 ) {
   173         return NULL;
   174     }
   175     char **strv = g_strsplit(keysym,":",2);
   176     if( strv[1] == NULL ) {
   177         /* root device */
   178         if( display_driver == NULL || display_driver->resolve_keysym == NULL) {
   179             // Root device has no input handling
   180             g_strfreev(strv);
   181             return NULL;
   182         }
   183         uint16_t keycode = display_driver->resolve_keysym(g_strstrip(strv[0]));
   184         g_strfreev(strv);
   185         if( keycode == 0 ) {
   186             return NULL;
   187         }
   188         return &root_keymap[keycode-1];
   190     } else {
   191         char *id = g_strstrip(strv[0]);
   192         GList *ptr;
   193         for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   194             input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   195             if( strcasecmp( entry->driver->id, id ) == 0 ) {
   196                 /* we have ze device */
   197                 if( entry->driver->resolve_keysym == NULL ) {
   198                     g_strfreev(strv);
   199                     return NULL;
   200                 } 
   201                 uint16_t keycode = entry->driver->resolve_keysym(entry->driver, g_strstrip(strv[1]));
   202                 g_strfreev(strv);
   203                 if( keycode == 0 || keycode > entry->entry_count ) {
   204                     return NULL;
   205                 }
   206                 return &entry->keymap[keycode-1];
   207             }
   208         }
   209         g_strfreev(strv);
   210         return NULL; // device not found
   211     }
   212 }
   214 static struct keymap_entry **input_entry_from_keycode( input_driver_t driver, uint16_t keycode )
   215 {
   216     GList *ptr;
   218     if( keycode == 0 ) {
   219         return NULL;
   220     }
   222     if( driver == NULL ) {
   223         return &root_keymap[keycode-1];
   224     }
   226     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   227         input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   228         if( entry->driver == driver ) {
   229             if( keycode > entry->entry_count ) {
   230                 return NULL;
   231             } else {
   232                 return &entry->keymap[keycode-1];
   233             }
   234         }
   235     }
   236     return NULL;
   237 }
   239 gchar *input_keycode_to_keysym( input_driver_t driver, uint16_t keycode )
   240 {
   241     if( keycode == 0 ) {
   242         return NULL;
   243     }
   244     if( driver == NULL ) {
   245         if( display_driver != NULL && display_driver->get_keysym_for_keycode != NULL ) {
   246             return display_driver->get_keysym_for_keycode(keycode);
   247         }
   248     } else if( driver->get_keysym_for_keycode ) {
   249         gchar *sym = driver->get_keysym_for_keycode(driver,keycode);
   250         if( sym != NULL ) {
   251             gchar *result = g_strdup_printf( "%s: %s", driver->id, sym );
   252             g_free(sym);
   253             return result;
   254         }
   255     }
   256     return NULL;
   257 }
   260 gboolean input_register_key( const gchar *keysym, input_key_callback_t callback,
   261                              void *data, uint32_t value )
   262 {
   263     if( keysym == NULL ) {
   264         return FALSE;
   265     }
   266     int keys = 0;
   267     gchar **strv = g_strsplit(keysym, ",", 16);
   268     gchar **s = strv;
   269     while( *s != NULL ) {
   270         keymap_entry_t *entryp = input_entry_from_keysym(*s);
   271         if( entryp != NULL ) {
   272             keymap_entry_t newentry = g_malloc0(sizeof(struct keymap_entry));
   273             newentry->next = *entryp;
   274             newentry->callback = callback;
   275             newentry->data = data;
   276             newentry->value = value;
   277             *entryp = newentry;
   278             keys++;
   279         }
   280         s++;
   281     }
   282     g_strfreev(strv);
   283     return keys != 0;
   284 }
   286 void input_unregister_key( const gchar *keysym, input_key_callback_t callback,
   287                            void *data, uint32_t value )
   288 {
   289     if( keysym == NULL ) {
   290         return;
   291     }
   293     gchar **strv = g_strsplit(keysym, ",", 16);
   294     gchar **s = strv;
   295     while( *s != NULL ) {
   296         keymap_entry_t *entryp = input_entry_from_keysym(*s);
   297         if( entryp != NULL ) {
   298             while( *entryp != NULL ) {
   299                 if( (*entryp)->callback == callback &&
   300                     (*entryp)->data == data && (*entryp)->value == value ) {
   301                     keymap_entry_t next = (*entryp)->next;
   302                     g_free( *entryp );
   303                     *entryp = next;
   304                     break;
   305                 }
   306                 entryp = &(*entryp)->next; // Yes, really
   307             }
   308         }
   309         s++;
   310     }
   311     g_strfreev(strv);
   312 }
   314 int input_register_keygroup( lxdream_config_group_t group)
   315 {
   316     int i;
   317     int result = 0;
   318     for( i=0; group->params[i].key != NULL; i++ ) {
   319         if( group->params[i].type == CONFIG_TYPE_KEY ) {
   320             if( input_register_key( group->params[i].value, group->key_binding, group->data, group->params[i].tag ) ) {
   321                 result++;
   322             }
   323         }
   324     }
   325     return result;
   326 }
   328 void input_unregister_keygroup( lxdream_config_group_t group )
   329 {
   330     int i;
   331     for( i=0; group->params[i].key != NULL; i++ ) {
   332         if( group->params[i].type == CONFIG_TYPE_KEY ) {
   333             input_unregister_key( group->params[i].value, group->key_binding, group->data, group->params[i].tag );
   334         }
   335     }
   336 }
   338 gboolean input_keygroup_changed( void *data, lxdream_config_group_t group, unsigned key,
   339                                  const gchar *oldval, const gchar *newval )
   340 {
   341     input_unregister_key( oldval, group->key_binding, group->data, group->params[key].tag );
   342     input_register_key( newval, group->key_binding, group->data, group->params[key].tag );
   343     return TRUE;
   344 }
   346 gboolean input_register_keyboard_hook( input_key_callback_t callback,
   347                               void *data )
   348 {
   349     keymap_entry_t key = malloc( sizeof( struct keymap_entry ) );
   350     assert( key != NULL );
   351     key->callback = callback;
   352     key->data = data;
   353     key->next = keyhooks;
   354     keyhooks = key;
   355     return TRUE;
   356 }
   358 void input_unregister_keyboard_hook( input_key_callback_t callback,
   359                             void *data )
   360 {
   361     keymap_entry_t key = keyhooks;
   362     if( key != NULL ) {
   363         if( key->callback == callback && key->data == data ) {
   364             keyhooks = keyhooks->next;
   365             free(key);
   366             return;
   367         }
   368         while( key->next != NULL ) {
   369             if( key->next->callback == callback && key->next->data == data ) {
   370                 keymap_entry_t next = key->next;
   371                 key->next = next->next;
   372                 free(next);
   373                 return;
   374             }
   375             key = key->next;
   376         }
   377     }
   378 }
   380 gboolean input_is_key_valid( const gchar *keysym )
   381 {
   382     keymap_entry_t *ptr = input_entry_from_keysym(keysym);
   383     return ptr != NULL;
   384 }
   386 gboolean input_is_key_registered( const gchar *keysym )
   387 {
   388     keymap_entry_t *ptr = input_entry_from_keysym(keysym);
   389     return ptr != NULL && *ptr != NULL;
   390 }
   392 void input_event_keydown( input_driver_t driver, uint16_t keycode, uint32_t pressure )
   393 {
   394     if( display_focused ) {
   395         keymap_entry_t *entryp = input_entry_from_keycode(driver,keycode);
   396         if( entryp != NULL ) {
   397             keymap_entry_t key = *entryp;
   398             while( key != NULL ) {
   399                 key->callback( key->data, key->value, pressure, TRUE );
   400                 key = key->next;
   401             }
   402         }
   403         if( driver == NULL ) {
   404             keymap_entry_t key = keyhooks;
   405             while( key != NULL ) {
   406                 key->callback( key->data, keycode, pressure, TRUE );
   407                 key = key->next;
   408             }
   409         }
   410     }
   411     if( display_keysym_hook != NULL ) {
   412         gchar *sym = input_keycode_to_keysym( driver, keycode );
   413         if( sym != NULL ) {
   414             display_keysym_hook(display_keysym_hook_data, sym);
   415             g_free(sym);
   416         }
   417     }
   418 }
   420 void input_event_keyup( input_driver_t driver, uint16_t keycode )
   421 {
   422     if( display_focused ) {
   423         keymap_entry_t *entryp = input_entry_from_keycode(driver,keycode);
   424         if( entryp != NULL ) {
   425             keymap_entry_t key = *entryp;
   426             while( key != NULL ) {
   427                 key->callback( key->data, key->value, 0, FALSE );
   428                 key = key->next;
   429             }
   430         }
   432         if( driver == NULL ) {
   433             keymap_entry_t key = keyhooks;
   434             while( key != NULL ) {
   435                 key->callback( key->data, keycode, 0, FALSE );
   436                 key = key->next;
   437             }
   438         }
   439     }
   440 }
   442 uint16_t input_keycode_to_dckeysym( uint16_t keycode )
   443 {
   444     return display_driver->convert_to_dckeysym(keycode);
   445 }
   447 void input_set_keysym_hook( display_keysym_callback_t hook, void *data )
   448 {
   449     display_keysym_hook = hook;
   450     display_keysym_hook_data = data;
   451 }
   453 /***************** System mouse driver ****************/
   455 static struct keymap_entry *mouse_keymap[MAX_MOUSE_BUTTONS];
   456 static struct mouse_entry *mousehooks = NULL;
   457 static uint32_t mouse_x = -1, mouse_y = -1, mouse_buttons = 0;
   459 uint16_t mouse_resolve_keysym( struct input_driver *driver, const gchar *keysym )
   460 {
   461     if( strncasecmp( keysym, "Button", 6 ) == 0 ){
   462         unsigned long button = strtoul( keysym+6, NULL, 10 );
   463         if( button > MAX_MOUSE_BUTTONS ) {
   464             return 0;
   465         }
   466         return (uint16_t)button;
   467     }
   468     return 0;
   469 }
   471 gchar *mouse_get_keysym( struct input_driver *driver, uint16_t keycode )
   472 {
   473     return g_strdup_printf( "Button%d", (keycode) );
   474 }
   476 struct input_driver system_mouse_driver = { "Mouse", mouse_resolve_keysym, NULL, mouse_get_keysym, NULL };
   479 gboolean input_register_mouse_hook( gboolean relative, input_mouse_callback_t callback,
   480                                     void *data )
   481 {
   482     mouse_entry_t ent = malloc( sizeof( struct mouse_entry ) );
   483     assert( ent != NULL );
   484     ent->callback = callback;
   485     ent->data = data;
   486     ent->next = mousehooks;
   487     mousehooks = ent;
   488     return TRUE;
   489 }    
   491 void input_unregister_mouse_hook( input_mouse_callback_t callback, void *data )
   492 {
   493     mouse_entry_t ent = mousehooks;
   494     if( ent != NULL ) {
   495         if( ent->callback == callback && ent->data == data ) {
   496             mousehooks = mousehooks->next;
   497             free(ent);
   498             return;
   499         }
   500         while( ent->next != NULL ) {
   501             if( ent->next->callback == callback && ent->next->data == data ) {
   502                 mouse_entry_t next = ent->next;
   503                 ent->next = next->next;
   504                 free(next);
   505                 return;
   506             }
   507             ent = ent->next;
   508         }
   509     }
   510 }
   512 void input_event_run_mouse_hooks( uint32_t buttons, int32_t x, int32_t y, gboolean absolute )
   513 {
   514     mouse_entry_t ent = mousehooks;
   515     while( ent != NULL ) {
   516         ent->callback(ent->data, buttons, x, y, absolute);
   517         ent = ent->next;
   518     }
   519 }
   521 void input_event_mousedown( uint16_t button, int32_t x, int32_t y, gboolean absolute )
   522 {
   523     if( absolute ) {
   524         mouse_x = x;
   525         mouse_y = y;
   526     }
   527     mouse_buttons |= (1<<button);
   528     input_event_keydown( &system_mouse_driver, button+1, MAX_PRESSURE );
   529     input_event_run_mouse_hooks( mouse_buttons, x, y, absolute );
   530 }    
   532 void input_event_mouseup( uint16_t button, int32_t x, int32_t y, gboolean absolute )
   533 {
   534     if( absolute ) {
   535         mouse_x = x;
   536         mouse_y = y;
   537     }
   538     mouse_buttons &= ~(1<<button);
   539     input_event_keyup( &system_mouse_driver, button+1 );
   540     input_event_run_mouse_hooks( mouse_buttons, x, y, absolute );
   541 }
   543 void input_event_mousemove( int32_t x, int32_t y, gboolean absolute )
   544 {
   545     if( absolute ) {
   546         mouse_x = x;
   547         mouse_y = y;
   548     }
   549     input_event_run_mouse_hooks( mouse_buttons, x, y, absolute );
   550 }
   552 /************************ Main display driver *************************/
   554 void print_display_drivers( FILE *out )
   555 {
   556     int i;
   557     fprintf( out, "Available video drivers:\n" );
   558     for( i=0; display_driver_list[i] != NULL; i++ ) {
   559         fprintf( out, "  %-8s %s\n", display_driver_list[i]->name,
   560                 gettext(display_driver_list[i]->description) );
   561     }
   562 }
   564 display_driver_t get_display_driver_by_name( const char *name )
   565 {
   566     int i;
   567     if( name == NULL ) {
   568         return display_driver_list[0];
   569     }
   570     for( i=0; display_driver_list[i] != NULL; i++ ) {
   571         if( strcasecmp( display_driver_list[i]->name, name ) == 0 ) {
   572             return display_driver_list[i];
   573         }
   574     }
   576     return NULL;
   577 }
   580 gboolean display_set_driver( display_driver_t driver )
   581 {
   582     gboolean rv = TRUE;
   583     if( display_driver != NULL && display_driver->shutdown_driver != NULL ) 
   584         display_driver->shutdown_driver();
   586     display_driver = driver;
   587     if( driver->init_driver != NULL )
   588         rv = driver->init_driver();
   589     if( rv ) {
   590         input_register_device(&system_mouse_driver, MAX_MOUSE_BUTTONS);
   591     } else {
   592         display_driver = NULL;
   593     }
   594     return rv;
   595 }
   597 void display_set_focused( gboolean has_focus )
   598 {
   599     display_focused = has_focus;
   600 }
.