Search
lxdream.org :: lxdream/src/display.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/display.c
changeset 1019:87f191f92f8f
prev1010:a506a2f66180
next1072:d82e04e6d497
author nkeynes
date Wed Jun 03 10:29:16 2009 +0000 (11 years ago)
permissions -rw-r--r--
last change Allow multiple input hooks to be registered for the same key - useful to allow
eg binding the same hotkey for run/stop so that it works as a toggle.
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     struct keymap_entry *next; // allow chaining
    60 } *keymap_entry_t;
    62 typedef struct mouse_entry {
    63     gboolean relative;
    64     input_mouse_callback_t callback;
    65     void *data;
    66     struct mouse_entry *next;
    67 } *mouse_entry_t;
    69 typedef struct input_driver_entry {
    70     input_driver_t driver;
    71     uint16_t entry_count;
    72     struct keymap_entry *keymap[0];
    73 } *input_driver_entry_t;
    75 /**
    76  * Colour format information
    77  */
    78 struct colour_format colour_formats[] = {
    79         { GL_UNSIGNED_SHORT_1_5_5_5_REV, GL_BGRA, GL_RGB5_A1, 2 },
    80         { GL_UNSIGNED_SHORT_5_6_5, GL_RGB, GL_RGB5, 2 },
    81         { GL_UNSIGNED_SHORT_4_4_4_4_REV, GL_BGRA, GL_RGBA4, 2 },
    82         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* YUV decoded to ARGB8888 */
    83         { GL_UNSIGNED_BYTE, GL_BGR, GL_RGB, 3 },
    84         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 },
    85         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* Index4 decoded */
    86         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* Index8 decoded */
    87         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 },
    88         { GL_UNSIGNED_BYTE, GL_RGB, GL_RGB, 3 },
    90 };
    92 /**
    93  * FIXME: make this more memory efficient
    94  */
    95 static struct keymap_entry *root_keymap[65535];
    96 static struct keymap_entry *keyhooks = NULL;
    97 static gboolean display_focused = TRUE;
    98 static GList *input_drivers= NULL;
    99 static display_keysym_callback_t display_keysym_hook = NULL;
   100 void *display_keysym_hook_data;
   102 gboolean input_register_device( input_driver_t driver, uint16_t max_keycode )
   103 {
   104     GList *ptr;
   105     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   106         input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   107         if( strcasecmp( entry->driver->id, driver->id ) == 0 ) {
   108             return FALSE;
   109         }
   110     }
   112     input_driver_entry_t entry = g_malloc0( sizeof(struct input_driver_entry) + (sizeof(keymap_entry_t) * max_keycode) );
   113     entry->driver = driver;
   114     entry->entry_count = max_keycode;
   115     input_drivers = g_list_append( input_drivers, entry );
   116     return TRUE;
   117 }
   119 gboolean input_has_device( const gchar *id )
   120 {
   121     GList *ptr;
   122     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   123         input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   124         if( strcasecmp(entry->driver->id, id) == 0 ) {
   125             return TRUE;
   126         }
   127     }
   128     return FALSE;
   129 }
   132 void input_unregister_device( input_driver_t driver )
   133 {
   134     GList *ptr;
   135     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   136         input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   137         if( entry->driver == driver ) {
   138             if( driver->destroy != NULL ) {
   139                 driver->destroy(driver);
   140             }
   141             input_drivers = g_list_remove(input_drivers, (gpointer)entry);
   142             g_free( entry );
   143             return;
   144         }
   145     }
   146 }
   148 /**
   149  * Resolve the keysym and return a pointer to the keymap entry pointer
   150  * @return keymap pointer or NULL if the key was unresolved
   151  */
   152 static struct keymap_entry **input_entry_from_keysym( const gchar *keysym )
   153 {
   154     if( keysym == NULL || keysym[0] == 0 ) {
   155         return NULL;
   156     }
   157     char **strv = g_strsplit(keysym,":",2);
   158     if( strv[1] == NULL ) {
   159         /* root device */
   160         if( display_driver == NULL || display_driver->resolve_keysym == NULL) {
   161             // Root device has no input handling
   162             g_strfreev(strv);
   163             return NULL;
   164         }
   165         uint16_t keycode = display_driver->resolve_keysym(g_strstrip(strv[0]));
   166         g_strfreev(strv);
   167         if( keycode == 0 ) {
   168             return NULL;
   169         }
   170         return &root_keymap[keycode-1];
   172     } else {
   173         char *id = g_strstrip(strv[0]);
   174         GList *ptr;
   175         for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   176             input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   177             if( strcasecmp( entry->driver->id, id ) == 0 ) {
   178                 /* we have ze device */
   179                 if( entry->driver->resolve_keysym == NULL ) {
   180                     g_strfreev(strv);
   181                     return NULL;
   182                 } 
   183                 uint16_t keycode = entry->driver->resolve_keysym(entry->driver, g_strstrip(strv[1]));
   184                 g_strfreev(strv);
   185                 if( keycode == 0 || keycode > entry->entry_count ) {
   186                     return NULL;
   187                 }
   188                 return &entry->keymap[keycode-1];
   189             }
   190         }
   191         g_strfreev(strv);
   192         return NULL; // device not found
   193     }
   194 }
   196 static struct keymap_entry **input_entry_from_keycode( input_driver_t driver, uint16_t keycode )
   197 {
   198     GList *ptr;
   200     if( keycode == 0 ) {
   201         return NULL;
   202     }
   204     if( driver == NULL ) {
   205         return &root_keymap[keycode-1];
   206     }
   208     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   209         input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   210         if( entry->driver == driver ) {
   211             if( keycode > entry->entry_count ) {
   212                 return NULL;
   213             } else {
   214                 return &entry->keymap[keycode-1];
   215             }
   216         }
   217     }
   218     return NULL;
   219 }
   221 gchar *input_keycode_to_keysym( input_driver_t driver, uint16_t keycode )
   222 {
   223     if( keycode == 0 ) {
   224         return NULL;
   225     }
   226     if( driver == NULL ) {
   227         if( display_driver != NULL && display_driver->get_keysym_for_keycode != NULL ) {
   228             return display_driver->get_keysym_for_keycode(keycode);
   229         }
   230     } else if( driver->get_keysym_for_keycode ) {
   231         gchar *sym = driver->get_keysym_for_keycode(driver,keycode);
   232         if( sym != NULL ) {
   233             gchar *result = g_strdup_printf( "%s: %s", driver->id, sym );
   234             g_free(sym);
   235             return result;
   236         }
   237     }
   238     return NULL;
   239 }
   242 gboolean input_register_key( const gchar *keysym, input_key_callback_t callback,
   243                              void *data, uint32_t value )
   244 {
   245     if( keysym == NULL ) {
   246         return FALSE;
   247     }
   248     int keys = 0;
   249     gchar **strv = g_strsplit(keysym, ",", 16);
   250     gchar **s = strv;
   251     while( *s != NULL ) {
   252         keymap_entry_t *entryp = input_entry_from_keysym(*s);
   253         if( entryp != NULL ) {
   254             keymap_entry_t newentry = g_malloc0(sizeof(struct keymap_entry));
   255             newentry->next = *entryp;
   256             newentry->callback = callback;
   257             newentry->data = data;
   258             newentry->value = value;
   259             *entryp = newentry;
   260             keys++;
   261         }
   262         s++;
   263     }
   264     g_strfreev(strv);
   265     return keys != 0;
   266 }
   268 void input_unregister_key( const gchar *keysym, input_key_callback_t callback,
   269                            void *data, uint32_t value )
   270 {
   271     if( keysym == NULL ) {
   272         return;
   273     }
   275     gchar **strv = g_strsplit(keysym, ",", 16);
   276     gchar **s = strv;
   277     while( *s != NULL ) {
   278         keymap_entry_t *entryp = input_entry_from_keysym(*s);
   279         if( entryp != NULL ) {
   280             while( *entryp != NULL ) {
   281                 if( (*entryp)->callback == callback &&
   282                     (*entryp)->data == data && (*entryp)->value == value ) {
   283                     keymap_entry_t next = (*entryp)->next;
   284                     g_free( *entryp );
   285                     *entryp = next;
   286                     break;
   287                 }
   288                 entryp = &(*entryp)->next; // Yes, really
   289             }
   290         }
   291         s++;
   292     }
   293     g_strfreev(strv);
   294 }
   296 gboolean input_register_keyboard_hook( input_key_callback_t callback,
   297                               void *data )
   298 {
   299     keymap_entry_t key = malloc( sizeof( struct keymap_entry ) );
   300     assert( key != NULL );
   301     key->callback = callback;
   302     key->data = data;
   303     key->next = keyhooks;
   304     keyhooks = key;
   305     return TRUE;
   306 }
   308 void input_unregister_keyboard_hook( input_key_callback_t callback,
   309                             void *data )
   310 {
   311     keymap_entry_t key = keyhooks;
   312     if( key != NULL ) {
   313         if( key->callback == callback && key->data == data ) {
   314             keyhooks = keyhooks->next;
   315             free(key);
   316             return;
   317         }
   318         while( key->next != NULL ) {
   319             if( key->next->callback == callback && key->next->data == data ) {
   320                 keymap_entry_t next = key->next;
   321                 key->next = next->next;
   322                 free(next);
   323                 return;
   324             }
   325             key = key->next;
   326         }
   327     }
   328 }
   330 gboolean input_is_key_valid( const gchar *keysym )
   331 {
   332     keymap_entry_t *ptr = input_entry_from_keysym(keysym);
   333     return ptr != NULL;
   334 }
   336 gboolean input_is_key_registered( const gchar *keysym )
   337 {
   338     keymap_entry_t *ptr = input_entry_from_keysym(keysym);
   339     return ptr != NULL && *ptr != NULL;
   340 }
   342 void input_event_keydown( input_driver_t driver, uint16_t keycode, uint32_t pressure )
   343 {
   344     if( display_focused ) {
   345         keymap_entry_t *entryp = input_entry_from_keycode(driver,keycode);
   346         if( entryp != NULL ) {
   347             keymap_entry_t key = *entryp;
   348             while( key != NULL ) {
   349                 key->callback( key->data, key->value, pressure, TRUE );
   350                 key = key->next;
   351             }
   352         }
   353         if( driver == NULL ) {
   354             keymap_entry_t key = keyhooks;
   355             while( key != NULL ) {
   356                 key->callback( key->data, keycode, pressure, TRUE );
   357                 key = key->next;
   358             }
   359         }
   360     }
   361     if( display_keysym_hook != NULL ) {
   362         gchar *sym = input_keycode_to_keysym( driver, keycode );
   363         if( sym != NULL ) {
   364             display_keysym_hook(display_keysym_hook_data, sym);
   365             g_free(sym);
   366         }
   367     }
   368 }
   370 void input_event_keyup( input_driver_t driver, uint16_t keycode )
   371 {
   372     if( display_focused ) {
   373         keymap_entry_t *entryp = input_entry_from_keycode(driver,keycode);
   374         if( entryp != NULL ) {
   375             keymap_entry_t key = *entryp;
   376             while( key != NULL ) {
   377                 key->callback( key->data, key->value, 0, FALSE );
   378                 key = key->next;
   379             }
   380         }
   382         if( driver == NULL ) {
   383             keymap_entry_t key = keyhooks;
   384             while( key != NULL ) {
   385                 key->callback( key->data, keycode, 0, FALSE );
   386                 key = key->next;
   387             }
   388         }
   389     }
   390 }
   392 uint16_t input_keycode_to_dckeysym( uint16_t keycode )
   393 {
   394     return display_driver->convert_to_dckeysym(keycode);
   395 }
   397 void input_set_keysym_hook( display_keysym_callback_t hook, void *data )
   398 {
   399     display_keysym_hook = hook;
   400     display_keysym_hook_data = data;
   401 }
   403 /***************** System mouse driver ****************/
   405 static struct keymap_entry *mouse_keymap[MAX_MOUSE_BUTTONS];
   406 static struct mouse_entry *mousehooks = NULL;
   407 static uint32_t mouse_x = -1, mouse_y = -1, mouse_buttons = 0;
   409 uint16_t mouse_resolve_keysym( struct input_driver *driver, const gchar *keysym )
   410 {
   411     if( strncasecmp( keysym, "Button", 6 ) == 0 ){
   412         unsigned long button = strtoul( keysym+6, NULL, 10 );
   413         if( button > MAX_MOUSE_BUTTONS ) {
   414             return 0;
   415         }
   416         return (uint16_t)button;
   417     }
   418     return 0;
   419 }
   421 gchar *mouse_get_keysym( struct input_driver *driver, uint16_t keycode )
   422 {
   423     return g_strdup_printf( "Button%d", (keycode) );
   424 }
   426 struct input_driver system_mouse_driver = { "Mouse", mouse_resolve_keysym, NULL, mouse_get_keysym, NULL };
   429 gboolean input_register_mouse_hook( gboolean relative, input_mouse_callback_t callback,
   430                                     void *data )
   431 {
   432     mouse_entry_t ent = malloc( sizeof( struct mouse_entry ) );
   433     assert( ent != NULL );
   434     ent->callback = callback;
   435     ent->data = data;
   436     ent->next = mousehooks;
   437     mousehooks = ent;
   438     return TRUE;
   439 }    
   441 void input_unregister_mouse_hook( input_mouse_callback_t callback, void *data )
   442 {
   443     mouse_entry_t ent = mousehooks;
   444     if( ent != NULL ) {
   445         if( ent->callback == callback && ent->data == data ) {
   446             mousehooks = mousehooks->next;
   447             free(ent);
   448             return;
   449         }
   450         while( ent->next != NULL ) {
   451             if( ent->next->callback == callback && ent->next->data == data ) {
   452                 mouse_entry_t next = ent->next;
   453                 ent->next = next->next;
   454                 free(next);
   455                 return;
   456             }
   457             ent = ent->next;
   458         }
   459     }
   460 }
   462 void input_event_run_mouse_hooks( uint32_t buttons, int32_t x, int32_t y, gboolean absolute )
   463 {
   464     mouse_entry_t ent = mousehooks;
   465     while( ent != NULL ) {
   466         ent->callback(ent->data, buttons, x, y, absolute);
   467         ent = ent->next;
   468     }
   469 }
   471 void input_event_mousedown( uint16_t button, int32_t x, int32_t y, gboolean absolute )
   472 {
   473     if( absolute ) {
   474         mouse_x = x;
   475         mouse_y = y;
   476     }
   477     mouse_buttons |= (1<<button);
   478     input_event_keydown( &system_mouse_driver, button+1, MAX_PRESSURE );
   479     input_event_run_mouse_hooks( mouse_buttons, x, y, absolute );
   480 }    
   482 void input_event_mouseup( uint16_t button, int32_t x, int32_t y, gboolean absolute )
   483 {
   484     if( absolute ) {
   485         mouse_x = x;
   486         mouse_y = y;
   487     }
   488     mouse_buttons &= ~(1<<button);
   489     input_event_keyup( &system_mouse_driver, button+1 );
   490     input_event_run_mouse_hooks( mouse_buttons, x, y, absolute );
   491 }
   493 void input_event_mousemove( int32_t x, int32_t y, gboolean absolute )
   494 {
   495     if( absolute ) {
   496         mouse_x = x;
   497         mouse_y = y;
   498     }
   499     input_event_run_mouse_hooks( mouse_buttons, x, y, absolute );
   500 }
   502 /************************ Main display driver *************************/
   504 void print_display_drivers( FILE *out )
   505 {
   506     int i;
   507     fprintf( out, "Available video drivers:\n" );
   508     for( i=0; display_driver_list[i] != NULL; i++ ) {
   509         fprintf( out, "  %-8s %s\n", display_driver_list[i]->name,
   510                 gettext(display_driver_list[i]->description) );
   511     }
   512 }
   514 display_driver_t get_display_driver_by_name( const char *name )
   515 {
   516     int i;
   517     if( name == NULL ) {
   518         return display_driver_list[0];
   519     }
   520     for( i=0; display_driver_list[i] != NULL; i++ ) {
   521         if( strcasecmp( display_driver_list[i]->name, name ) == 0 ) {
   522             return display_driver_list[i];
   523         }
   524     }
   526     return NULL;
   527 }
   530 gboolean display_set_driver( display_driver_t driver )
   531 {
   532     gboolean rv = TRUE;
   533     if( display_driver != NULL && display_driver->shutdown_driver != NULL ) 
   534         display_driver->shutdown_driver();
   536     display_driver = driver;
   537     if( driver->init_driver != NULL )
   538         rv = driver->init_driver();
   539     if( rv ) {
   540         input_register_device(&system_mouse_driver, MAX_MOUSE_BUTTONS);
   541     } else {
   542         display_driver = NULL;
   543     }
   544     return rv;
   545 }
   547 void display_set_focused( gboolean has_focus )
   548 {
   549     display_focused = has_focus;
   550 }
.