Search
lxdream.org :: lxdream/src/display.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/display.c
changeset 1239:be3121267597
prev1072:d82e04e6d497
next1244:6b54ef5ed413
author nkeynes
date Sat Feb 25 21:30:49 2012 +1000 (7 years ago)
permissions -rw-r--r--
last change Android support WIP
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         &display_null_driver,
    36         NULL };
    38 /* Some explanation:
    39  *   The system has at least one "root" device representing the main display 
    40  * (which may be the null display). This device is part of the display_driver
    41  * and generates events with no input_driver. The root device has no id
    42  * as such (for the purposes of event names)
    43  *
    44  *   The system may also have one or more auxilliary devices which each have
    45  * an input_driver and an id (eg "JS0"). So the keysym "Return" is (de)coded by
    46  * the root device, and the keysym "JS0: Button0" is (de)coded by the JS0 input
    47  * device as "Button0".
    48  *
    49  *   For the moment, mice are handled specially, as they behave a little
    50  * differently from other devices (although this will probably change in the 
    51  * future.
    52  */
    55 typedef struct keymap_entry {
    56     input_key_callback_t callback;
    57     void *data;
    58     uint32_t value;
    59     lxdream_config_group_t group;
    60     struct keymap_entry *next; // allow chaining
    61 } *keymap_entry_t;
    63 typedef struct mouse_entry {
    64     gboolean relative;
    65     input_mouse_callback_t callback;
    66     void *data;
    67     const lxdream_config_group_t group;
    68     struct mouse_entry *next;
    69 } *mouse_entry_t;
    71 typedef struct input_driver_entry {
    72     input_driver_t driver;
    73     uint16_t entry_count;
    74     struct keymap_entry *keymap[0];
    75 } *input_driver_entry_t;
    78 #ifndef GL_RGBA8
    79 #define GL_RGBA8 GL_RGBA8_OES
    80 #endif
    82 #ifndef GL_RGB5
    83 #define GL_RGB5 GL_RGB565
    84 #endif
    86 #ifndef GL_BGR
    87 #define GL_BGR GL_BGRA
    88 #endif
    90 /**
    91  * Colour format information
    92  */
    93 struct colour_format colour_formats[] = {
    94         { GL_UNSIGNED_SHORT_1_5_5_5_REV, GL_BGRA, GL_RGB5_A1, 2 },
    95         { GL_UNSIGNED_SHORT_5_6_5, GL_RGB, GL_RGB5, 2 },
    96         { GL_UNSIGNED_SHORT_4_4_4_4_REV, GL_BGRA, GL_RGBA4, 2 },
    97         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* YUV decoded to ARGB8888 */
    98         { GL_UNSIGNED_BYTE, GL_BGR, GL_RGB, 3 },
    99         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 },
   100         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* Index4 decoded */
   101         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* Index8 decoded */
   102         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 },
   103         { GL_UNSIGNED_BYTE, GL_RGB, GL_RGB, 3 },
   105 };
   107 /**
   108  * FIXME: make this more memory efficient
   109  */
   110 static struct keymap_entry *root_keymap[65535];
   111 static struct keymap_entry *keyhooks = NULL;
   112 static gboolean display_focused = TRUE;
   113 static GList *input_drivers= NULL;
   114 static display_keysym_callback_t display_keysym_hook = NULL;
   115 void *display_keysym_hook_data;
   117 gboolean input_register_device( input_driver_t driver, uint16_t max_keycode )
   118 {
   119     GList *ptr;
   120     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   121         input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   122         if( strcasecmp( entry->driver->id, driver->id ) == 0 ) {
   123             return FALSE;
   124         }
   125     }
   127     input_driver_entry_t entry = g_malloc0( sizeof(struct input_driver_entry) + (sizeof(keymap_entry_t) * max_keycode) );
   128     entry->driver = driver;
   129     entry->entry_count = max_keycode;
   130     input_drivers = g_list_append( input_drivers, entry );
   131     return TRUE;
   132 }
   134 gboolean input_has_device( const gchar *id )
   135 {
   136     GList *ptr;
   137     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   138         input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   139         if( strcasecmp(entry->driver->id, id) == 0 ) {
   140             return TRUE;
   141         }
   142     }
   143     return FALSE;
   144 }
   147 void input_unregister_device( input_driver_t driver )
   148 {
   149     GList *ptr;
   150     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   151         input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   152         if( entry->driver == driver ) {
   153             if( driver->destroy != NULL ) {
   154                 driver->destroy(driver);
   155             }
   156             input_drivers = g_list_remove(input_drivers, (gpointer)entry);
   157             g_free( entry );
   158             return;
   159         }
   160     }
   161 }
   163 /**
   164  * Resolve the keysym and return a pointer to the keymap entry pointer
   165  * @return keymap pointer or NULL if the key was unresolved
   166  */
   167 static struct keymap_entry **input_entry_from_keysym( const gchar *keysym )
   168 {
   169     if( keysym == NULL || keysym[0] == 0 ) {
   170         return NULL;
   171     }
   172     char **strv = g_strsplit(keysym,":",2);
   173     if( strv[1] == NULL ) {
   174         /* root device */
   175         if( display_driver == NULL || display_driver->resolve_keysym == NULL) {
   176             // Root device has no input handling
   177             g_strfreev(strv);
   178             return NULL;
   179         }
   180         uint16_t keycode = display_driver->resolve_keysym(g_strstrip(strv[0]));
   181         g_strfreev(strv);
   182         if( keycode == 0 ) {
   183             return NULL;
   184         }
   185         return &root_keymap[keycode-1];
   187     } else {
   188         char *id = g_strstrip(strv[0]);
   189         GList *ptr;
   190         for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   191             input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   192             if( strcasecmp( entry->driver->id, id ) == 0 ) {
   193                 /* we have ze device */
   194                 if( entry->driver->resolve_keysym == NULL ) {
   195                     g_strfreev(strv);
   196                     return NULL;
   197                 } 
   198                 uint16_t keycode = entry->driver->resolve_keysym(entry->driver, g_strstrip(strv[1]));
   199                 g_strfreev(strv);
   200                 if( keycode == 0 || keycode > entry->entry_count ) {
   201                     return NULL;
   202                 }
   203                 return &entry->keymap[keycode-1];
   204             }
   205         }
   206         g_strfreev(strv);
   207         return NULL; // device not found
   208     }
   209 }
   211 static struct keymap_entry **input_entry_from_keycode( input_driver_t driver, uint16_t keycode )
   212 {
   213     GList *ptr;
   215     if( keycode == 0 ) {
   216         return NULL;
   217     }
   219     if( driver == NULL ) {
   220         return &root_keymap[keycode-1];
   221     }
   223     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   224         input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   225         if( entry->driver == driver ) {
   226             if( keycode > entry->entry_count ) {
   227                 return NULL;
   228             } else {
   229                 return &entry->keymap[keycode-1];
   230             }
   231         }
   232     }
   233     return NULL;
   234 }
   236 gchar *input_keycode_to_keysym( input_driver_t driver, uint16_t keycode )
   237 {
   238     if( keycode == 0 ) {
   239         return NULL;
   240     }
   241     if( driver == NULL ) {
   242         if( display_driver != NULL && display_driver->get_keysym_for_keycode != NULL ) {
   243             return display_driver->get_keysym_for_keycode(keycode);
   244         }
   245     } else if( driver->get_keysym_for_keycode ) {
   246         gchar *sym = driver->get_keysym_for_keycode(driver,keycode);
   247         if( sym != NULL ) {
   248             gchar *result = g_strdup_printf( "%s: %s", driver->id, sym );
   249             g_free(sym);
   250             return result;
   251         }
   252     }
   253     return NULL;
   254 }
   257 gboolean input_register_key( const gchar *keysym, input_key_callback_t callback,
   258                              void *data, uint32_t value )
   259 {
   260     if( keysym == NULL ) {
   261         return FALSE;
   262     }
   263     int keys = 0;
   264     gchar **strv = g_strsplit(keysym, ",", 16);
   265     gchar **s = strv;
   266     while( *s != NULL ) {
   267         keymap_entry_t *entryp = input_entry_from_keysym(*s);
   268         if( entryp != NULL ) {
   269             keymap_entry_t newentry = g_malloc0(sizeof(struct keymap_entry));
   270             newentry->next = *entryp;
   271             newentry->callback = callback;
   272             newentry->data = data;
   273             newentry->value = value;
   274             *entryp = newentry;
   275             keys++;
   276         }
   277         s++;
   278     }
   279     g_strfreev(strv);
   280     return keys != 0;
   281 }
   283 void input_unregister_key( const gchar *keysym, input_key_callback_t callback,
   284                            void *data, uint32_t value )
   285 {
   286     if( keysym == NULL ) {
   287         return;
   288     }
   290     gchar **strv = g_strsplit(keysym, ",", 16);
   291     gchar **s = strv;
   292     while( *s != NULL ) {
   293         keymap_entry_t *entryp = input_entry_from_keysym(*s);
   294         if( entryp != NULL ) {
   295             while( *entryp != NULL ) {
   296                 if( (*entryp)->callback == callback &&
   297                     (*entryp)->data == data && (*entryp)->value == value ) {
   298                     keymap_entry_t next = (*entryp)->next;
   299                     g_free( *entryp );
   300                     *entryp = next;
   301                     break;
   302                 }
   303                 entryp = &(*entryp)->next; // Yes, really
   304             }
   305         }
   306         s++;
   307     }
   308     g_strfreev(strv);
   309 }
   311 int input_register_keygroup( lxdream_config_group_t group)
   312 {
   313     int i;
   314     int result = 0;
   315     for( i=0; group->params[i].key != NULL; i++ ) {
   316         if( group->params[i].type == CONFIG_TYPE_KEY ) {
   317             if( input_register_key( group->params[i].value, group->key_binding, group->data, group->params[i].tag ) ) {
   318                 result++;
   319             }
   320         }
   321     }
   322     return result;
   323 }
   325 void input_unregister_keygroup( lxdream_config_group_t group )
   326 {
   327     int i;
   328     for( i=0; group->params[i].key != NULL; i++ ) {
   329         if( group->params[i].type == CONFIG_TYPE_KEY ) {
   330             input_unregister_key( group->params[i].value, group->key_binding, group->data, group->params[i].tag );
   331         }
   332     }
   333 }
   335 gboolean input_keygroup_changed( void *data, lxdream_config_group_t group, unsigned key,
   336                                  const gchar *oldval, const gchar *newval )
   337 {
   338     input_unregister_key( oldval, group->key_binding, group->data, group->params[key].tag );
   339     input_register_key( newval, group->key_binding, group->data, group->params[key].tag );
   340     return TRUE;
   341 }
   343 gboolean input_register_keyboard_hook( input_key_callback_t callback,
   344                               void *data )
   345 {
   346     keymap_entry_t key = malloc( sizeof( struct keymap_entry ) );
   347     assert( key != NULL );
   348     key->callback = callback;
   349     key->data = data;
   350     key->next = keyhooks;
   351     keyhooks = key;
   352     return TRUE;
   353 }
   355 void input_unregister_keyboard_hook( input_key_callback_t callback,
   356                             void *data )
   357 {
   358     keymap_entry_t key = keyhooks;
   359     if( key != NULL ) {
   360         if( key->callback == callback && key->data == data ) {
   361             keyhooks = keyhooks->next;
   362             free(key);
   363             return;
   364         }
   365         while( key->next != NULL ) {
   366             if( key->next->callback == callback && key->next->data == data ) {
   367                 keymap_entry_t next = key->next;
   368                 key->next = next->next;
   369                 free(next);
   370                 return;
   371             }
   372             key = key->next;
   373         }
   374     }
   375 }
   377 gboolean input_is_key_valid( const gchar *keysym )
   378 {
   379     keymap_entry_t *ptr = input_entry_from_keysym(keysym);
   380     return ptr != NULL;
   381 }
   383 gboolean input_is_key_registered( const gchar *keysym )
   384 {
   385     keymap_entry_t *ptr = input_entry_from_keysym(keysym);
   386     return ptr != NULL && *ptr != NULL;
   387 }
   389 void input_event_keydown( input_driver_t driver, uint16_t keycode, uint32_t pressure )
   390 {
   391     if( display_focused ) {
   392         keymap_entry_t *entryp = input_entry_from_keycode(driver,keycode);
   393         if( entryp != NULL ) {
   394             keymap_entry_t key = *entryp;
   395             while( key != NULL ) {
   396                 key->callback( key->data, key->value, pressure, TRUE );
   397                 key = key->next;
   398             }
   399         }
   400         if( driver == NULL ) {
   401             keymap_entry_t key = keyhooks;
   402             while( key != NULL ) {
   403                 key->callback( key->data, keycode, pressure, TRUE );
   404                 key = key->next;
   405             }
   406         }
   407     }
   408     if( display_keysym_hook != NULL ) {
   409         gchar *sym = input_keycode_to_keysym( driver, keycode );
   410         if( sym != NULL ) {
   411             display_keysym_hook(display_keysym_hook_data, sym);
   412             g_free(sym);
   413         }
   414     }
   415 }
   417 void input_event_keyup( input_driver_t driver, uint16_t keycode )
   418 {
   419     if( display_focused ) {
   420         keymap_entry_t *entryp = input_entry_from_keycode(driver,keycode);
   421         if( entryp != NULL ) {
   422             keymap_entry_t key = *entryp;
   423             while( key != NULL ) {
   424                 key->callback( key->data, key->value, 0, FALSE );
   425                 key = key->next;
   426             }
   427         }
   429         if( driver == NULL ) {
   430             keymap_entry_t key = keyhooks;
   431             while( key != NULL ) {
   432                 key->callback( key->data, keycode, 0, FALSE );
   433                 key = key->next;
   434             }
   435         }
   436     }
   437 }
   439 uint16_t input_keycode_to_dckeysym( uint16_t keycode )
   440 {
   441     return display_driver->convert_to_dckeysym(keycode);
   442 }
   444 void input_set_keysym_hook( display_keysym_callback_t hook, void *data )
   445 {
   446     display_keysym_hook = hook;
   447     display_keysym_hook_data = data;
   448 }
   450 /***************** System mouse driver ****************/
   452 static struct keymap_entry *mouse_keymap[MAX_MOUSE_BUTTONS];
   453 static struct mouse_entry *mousehooks = NULL;
   454 static uint32_t mouse_x = -1, mouse_y = -1, mouse_buttons = 0;
   456 uint16_t mouse_resolve_keysym( struct input_driver *driver, const gchar *keysym )
   457 {
   458     if( strncasecmp( keysym, "Button", 6 ) == 0 ){
   459         unsigned long button = strtoul( keysym+6, NULL, 10 );
   460         if( button > MAX_MOUSE_BUTTONS ) {
   461             return 0;
   462         }
   463         return (uint16_t)button;
   464     }
   465     return 0;
   466 }
   468 gchar *mouse_get_keysym( struct input_driver *driver, uint16_t keycode )
   469 {
   470     return g_strdup_printf( "Button%d", (keycode) );
   471 }
   473 struct input_driver system_mouse_driver = { "Mouse", mouse_resolve_keysym, NULL, mouse_get_keysym, NULL };
   476 gboolean input_register_mouse_hook( gboolean relative, input_mouse_callback_t callback,
   477                                     void *data )
   478 {
   479     mouse_entry_t ent = malloc( sizeof( struct mouse_entry ) );
   480     assert( ent != NULL );
   481     ent->callback = callback;
   482     ent->data = data;
   483     ent->next = mousehooks;
   484     mousehooks = ent;
   485     return TRUE;
   486 }    
   488 void input_unregister_mouse_hook( input_mouse_callback_t callback, void *data )
   489 {
   490     mouse_entry_t ent = mousehooks;
   491     if( ent != NULL ) {
   492         if( ent->callback == callback && ent->data == data ) {
   493             mousehooks = mousehooks->next;
   494             free(ent);
   495             return;
   496         }
   497         while( ent->next != NULL ) {
   498             if( ent->next->callback == callback && ent->next->data == data ) {
   499                 mouse_entry_t next = ent->next;
   500                 ent->next = next->next;
   501                 free(next);
   502                 return;
   503             }
   504             ent = ent->next;
   505         }
   506     }
   507 }
   509 void input_event_run_mouse_hooks( uint32_t buttons, int32_t x, int32_t y, gboolean absolute )
   510 {
   511     mouse_entry_t ent = mousehooks;
   512     while( ent != NULL ) {
   513         ent->callback(ent->data, buttons, x, y, absolute);
   514         ent = ent->next;
   515     }
   516 }
   518 void input_event_mousedown( uint16_t button, int32_t x, int32_t y, gboolean absolute )
   519 {
   520     if( absolute ) {
   521         mouse_x = x;
   522         mouse_y = y;
   523     }
   524     mouse_buttons |= (1<<button);
   525     input_event_keydown( &system_mouse_driver, button+1, MAX_PRESSURE );
   526     input_event_run_mouse_hooks( mouse_buttons, x, y, absolute );
   527 }    
   529 void input_event_mouseup( uint16_t button, int32_t x, int32_t y, gboolean absolute )
   530 {
   531     if( absolute ) {
   532         mouse_x = x;
   533         mouse_y = y;
   534     }
   535     mouse_buttons &= ~(1<<button);
   536     input_event_keyup( &system_mouse_driver, button+1 );
   537     input_event_run_mouse_hooks( mouse_buttons, x, y, absolute );
   538 }
   540 void input_event_mousemove( int32_t x, int32_t y, gboolean absolute )
   541 {
   542     if( absolute ) {
   543         mouse_x = x;
   544         mouse_y = y;
   545     }
   546     input_event_run_mouse_hooks( mouse_buttons, x, y, absolute );
   547 }
   549 /************************ Main display driver *************************/
   551 void print_display_drivers( FILE *out )
   552 {
   553     int i;
   554     fprintf( out, "Available video drivers:\n" );
   555     for( i=0; display_driver_list[i] != NULL; i++ ) {
   556         fprintf( out, "  %-8s %s\n", display_driver_list[i]->name,
   557                 gettext(display_driver_list[i]->description) );
   558     }
   559 }
   561 display_driver_t get_display_driver_by_name( const char *name )
   562 {
   563     int i;
   564     if( name == NULL ) {
   565         return display_driver_list[0];
   566     }
   567     for( i=0; display_driver_list[i] != NULL; i++ ) {
   568         if( strcasecmp( display_driver_list[i]->name, name ) == 0 ) {
   569             return display_driver_list[i];
   570         }
   571     }
   573     return NULL;
   574 }
   577 gboolean display_set_driver( display_driver_t driver )
   578 {
   579     gboolean rv = TRUE;
   580     if( display_driver != NULL && display_driver->shutdown_driver != NULL ) 
   581         display_driver->shutdown_driver();
   583     display_driver = driver;
   584     if( driver->init_driver != NULL )
   585         rv = driver->init_driver();
   586     if( rv ) {
   587         input_register_device(&system_mouse_driver, MAX_MOUSE_BUTTONS);
   588     } else {
   589         display_driver = NULL;
   590     }
   591     return rv;
   592 }
   594 void display_set_focused( gboolean has_focus )
   595 {
   596     display_focused = has_focus;
   597 }
.