Search
lxdream.org :: lxdream/src/display.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/display.c
changeset 1072:d82e04e6d497
prev1019:87f191f92f8f
next1239:be3121267597
author nkeynes
date Tue Jul 21 20:33:21 2009 +1000 (11 years ago)
permissions -rw-r--r--
last change Heavy configuration management refactor
- Configuration groups now take both an on_change event handler and a
default keybinding handler, making most keybinding tasks quite simple
- GUI configuration all merged into a unified model, drastically reducing
the amount of GUI config code.

Bonuses
- OSX now has a hotkey preference pane
- GTK keybinding editor is much more usable
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;
    77 /**
    78  * Colour format information
    79  */
    80 struct colour_format colour_formats[] = {
    81         { GL_UNSIGNED_SHORT_1_5_5_5_REV, GL_BGRA, GL_RGB5_A1, 2 },
    82         { GL_UNSIGNED_SHORT_5_6_5, GL_RGB, GL_RGB5, 2 },
    83         { GL_UNSIGNED_SHORT_4_4_4_4_REV, GL_BGRA, GL_RGBA4, 2 },
    84         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* YUV decoded to ARGB8888 */
    85         { GL_UNSIGNED_BYTE, GL_BGR, GL_RGB, 3 },
    86         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 },
    87         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* Index4 decoded */
    88         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* Index8 decoded */
    89         { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 },
    90         { GL_UNSIGNED_BYTE, GL_RGB, GL_RGB, 3 },
    92 };
    94 /**
    95  * FIXME: make this more memory efficient
    96  */
    97 static struct keymap_entry *root_keymap[65535];
    98 static struct keymap_entry *keyhooks = NULL;
    99 static gboolean display_focused = TRUE;
   100 static GList *input_drivers= NULL;
   101 static display_keysym_callback_t display_keysym_hook = NULL;
   102 void *display_keysym_hook_data;
   104 gboolean input_register_device( input_driver_t driver, uint16_t max_keycode )
   105 {
   106     GList *ptr;
   107     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   108         input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   109         if( strcasecmp( entry->driver->id, driver->id ) == 0 ) {
   110             return FALSE;
   111         }
   112     }
   114     input_driver_entry_t entry = g_malloc0( sizeof(struct input_driver_entry) + (sizeof(keymap_entry_t) * max_keycode) );
   115     entry->driver = driver;
   116     entry->entry_count = max_keycode;
   117     input_drivers = g_list_append( input_drivers, entry );
   118     return TRUE;
   119 }
   121 gboolean input_has_device( const gchar *id )
   122 {
   123     GList *ptr;
   124     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   125         input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   126         if( strcasecmp(entry->driver->id, id) == 0 ) {
   127             return TRUE;
   128         }
   129     }
   130     return FALSE;
   131 }
   134 void input_unregister_device( input_driver_t driver )
   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( entry->driver == driver ) {
   140             if( driver->destroy != NULL ) {
   141                 driver->destroy(driver);
   142             }
   143             input_drivers = g_list_remove(input_drivers, (gpointer)entry);
   144             g_free( entry );
   145             return;
   146         }
   147     }
   148 }
   150 /**
   151  * Resolve the keysym and return a pointer to the keymap entry pointer
   152  * @return keymap pointer or NULL if the key was unresolved
   153  */
   154 static struct keymap_entry **input_entry_from_keysym( const gchar *keysym )
   155 {
   156     if( keysym == NULL || keysym[0] == 0 ) {
   157         return NULL;
   158     }
   159     char **strv = g_strsplit(keysym,":",2);
   160     if( strv[1] == NULL ) {
   161         /* root device */
   162         if( display_driver == NULL || display_driver->resolve_keysym == NULL) {
   163             // Root device has no input handling
   164             g_strfreev(strv);
   165             return NULL;
   166         }
   167         uint16_t keycode = display_driver->resolve_keysym(g_strstrip(strv[0]));
   168         g_strfreev(strv);
   169         if( keycode == 0 ) {
   170             return NULL;
   171         }
   172         return &root_keymap[keycode-1];
   174     } else {
   175         char *id = g_strstrip(strv[0]);
   176         GList *ptr;
   177         for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   178             input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   179             if( strcasecmp( entry->driver->id, id ) == 0 ) {
   180                 /* we have ze device */
   181                 if( entry->driver->resolve_keysym == NULL ) {
   182                     g_strfreev(strv);
   183                     return NULL;
   184                 } 
   185                 uint16_t keycode = entry->driver->resolve_keysym(entry->driver, g_strstrip(strv[1]));
   186                 g_strfreev(strv);
   187                 if( keycode == 0 || keycode > entry->entry_count ) {
   188                     return NULL;
   189                 }
   190                 return &entry->keymap[keycode-1];
   191             }
   192         }
   193         g_strfreev(strv);
   194         return NULL; // device not found
   195     }
   196 }
   198 static struct keymap_entry **input_entry_from_keycode( input_driver_t driver, uint16_t keycode )
   199 {
   200     GList *ptr;
   202     if( keycode == 0 ) {
   203         return NULL;
   204     }
   206     if( driver == NULL ) {
   207         return &root_keymap[keycode-1];
   208     }
   210     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   211         input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   212         if( entry->driver == driver ) {
   213             if( keycode > entry->entry_count ) {
   214                 return NULL;
   215             } else {
   216                 return &entry->keymap[keycode-1];
   217             }
   218         }
   219     }
   220     return NULL;
   221 }
   223 gchar *input_keycode_to_keysym( input_driver_t driver, uint16_t keycode )
   224 {
   225     if( keycode == 0 ) {
   226         return NULL;
   227     }
   228     if( driver == NULL ) {
   229         if( display_driver != NULL && display_driver->get_keysym_for_keycode != NULL ) {
   230             return display_driver->get_keysym_for_keycode(keycode);
   231         }
   232     } else if( driver->get_keysym_for_keycode ) {
   233         gchar *sym = driver->get_keysym_for_keycode(driver,keycode);
   234         if( sym != NULL ) {
   235             gchar *result = g_strdup_printf( "%s: %s", driver->id, sym );
   236             g_free(sym);
   237             return result;
   238         }
   239     }
   240     return NULL;
   241 }
   244 gboolean input_register_key( const gchar *keysym, input_key_callback_t callback,
   245                              void *data, uint32_t value )
   246 {
   247     if( keysym == NULL ) {
   248         return FALSE;
   249     }
   250     int keys = 0;
   251     gchar **strv = g_strsplit(keysym, ",", 16);
   252     gchar **s = strv;
   253     while( *s != NULL ) {
   254         keymap_entry_t *entryp = input_entry_from_keysym(*s);
   255         if( entryp != NULL ) {
   256             keymap_entry_t newentry = g_malloc0(sizeof(struct keymap_entry));
   257             newentry->next = *entryp;
   258             newentry->callback = callback;
   259             newentry->data = data;
   260             newentry->value = value;
   261             *entryp = newentry;
   262             keys++;
   263         }
   264         s++;
   265     }
   266     g_strfreev(strv);
   267     return keys != 0;
   268 }
   270 void input_unregister_key( const gchar *keysym, input_key_callback_t callback,
   271                            void *data, uint32_t value )
   272 {
   273     if( keysym == NULL ) {
   274         return;
   275     }
   277     gchar **strv = g_strsplit(keysym, ",", 16);
   278     gchar **s = strv;
   279     while( *s != NULL ) {
   280         keymap_entry_t *entryp = input_entry_from_keysym(*s);
   281         if( entryp != NULL ) {
   282             while( *entryp != NULL ) {
   283                 if( (*entryp)->callback == callback &&
   284                     (*entryp)->data == data && (*entryp)->value == value ) {
   285                     keymap_entry_t next = (*entryp)->next;
   286                     g_free( *entryp );
   287                     *entryp = next;
   288                     break;
   289                 }
   290                 entryp = &(*entryp)->next; // Yes, really
   291             }
   292         }
   293         s++;
   294     }
   295     g_strfreev(strv);
   296 }
   298 int input_register_keygroup( lxdream_config_group_t group)
   299 {
   300     int i;
   301     int result = 0;
   302     for( i=0; group->params[i].key != NULL; i++ ) {
   303         if( group->params[i].type == CONFIG_TYPE_KEY ) {
   304             if( input_register_key( group->params[i].value, group->key_binding, group->data, group->params[i].tag ) ) {
   305                 result++;
   306             }
   307         }
   308     }
   309     return result;
   310 }
   312 void input_unregister_keygroup( lxdream_config_group_t group )
   313 {
   314     int i;
   315     for( i=0; group->params[i].key != NULL; i++ ) {
   316         if( group->params[i].type == CONFIG_TYPE_KEY ) {
   317             input_unregister_key( group->params[i].value, group->key_binding, group->data, group->params[i].tag );
   318         }
   319     }
   320 }
   322 gboolean input_keygroup_changed( void *data, lxdream_config_group_t group, unsigned key,
   323                                  const gchar *oldval, const gchar *newval )
   324 {
   325     input_unregister_key( oldval, group->key_binding, group->data, group->params[key].tag );
   326     input_register_key( newval, group->key_binding, group->data, group->params[key].tag );
   327     return TRUE;
   328 }
   330 gboolean input_register_keyboard_hook( input_key_callback_t callback,
   331                               void *data )
   332 {
   333     keymap_entry_t key = malloc( sizeof( struct keymap_entry ) );
   334     assert( key != NULL );
   335     key->callback = callback;
   336     key->data = data;
   337     key->next = keyhooks;
   338     keyhooks = key;
   339     return TRUE;
   340 }
   342 void input_unregister_keyboard_hook( input_key_callback_t callback,
   343                             void *data )
   344 {
   345     keymap_entry_t key = keyhooks;
   346     if( key != NULL ) {
   347         if( key->callback == callback && key->data == data ) {
   348             keyhooks = keyhooks->next;
   349             free(key);
   350             return;
   351         }
   352         while( key->next != NULL ) {
   353             if( key->next->callback == callback && key->next->data == data ) {
   354                 keymap_entry_t next = key->next;
   355                 key->next = next->next;
   356                 free(next);
   357                 return;
   358             }
   359             key = key->next;
   360         }
   361     }
   362 }
   364 gboolean input_is_key_valid( const gchar *keysym )
   365 {
   366     keymap_entry_t *ptr = input_entry_from_keysym(keysym);
   367     return ptr != NULL;
   368 }
   370 gboolean input_is_key_registered( const gchar *keysym )
   371 {
   372     keymap_entry_t *ptr = input_entry_from_keysym(keysym);
   373     return ptr != NULL && *ptr != NULL;
   374 }
   376 void input_event_keydown( input_driver_t driver, uint16_t keycode, uint32_t pressure )
   377 {
   378     if( display_focused ) {
   379         keymap_entry_t *entryp = input_entry_from_keycode(driver,keycode);
   380         if( entryp != NULL ) {
   381             keymap_entry_t key = *entryp;
   382             while( key != NULL ) {
   383                 key->callback( key->data, key->value, pressure, TRUE );
   384                 key = key->next;
   385             }
   386         }
   387         if( driver == NULL ) {
   388             keymap_entry_t key = keyhooks;
   389             while( key != NULL ) {
   390                 key->callback( key->data, keycode, pressure, TRUE );
   391                 key = key->next;
   392             }
   393         }
   394     }
   395     if( display_keysym_hook != NULL ) {
   396         gchar *sym = input_keycode_to_keysym( driver, keycode );
   397         if( sym != NULL ) {
   398             display_keysym_hook(display_keysym_hook_data, sym);
   399             g_free(sym);
   400         }
   401     }
   402 }
   404 void input_event_keyup( input_driver_t driver, uint16_t keycode )
   405 {
   406     if( display_focused ) {
   407         keymap_entry_t *entryp = input_entry_from_keycode(driver,keycode);
   408         if( entryp != NULL ) {
   409             keymap_entry_t key = *entryp;
   410             while( key != NULL ) {
   411                 key->callback( key->data, key->value, 0, FALSE );
   412                 key = key->next;
   413             }
   414         }
   416         if( driver == NULL ) {
   417             keymap_entry_t key = keyhooks;
   418             while( key != NULL ) {
   419                 key->callback( key->data, keycode, 0, FALSE );
   420                 key = key->next;
   421             }
   422         }
   423     }
   424 }
   426 uint16_t input_keycode_to_dckeysym( uint16_t keycode )
   427 {
   428     return display_driver->convert_to_dckeysym(keycode);
   429 }
   431 void input_set_keysym_hook( display_keysym_callback_t hook, void *data )
   432 {
   433     display_keysym_hook = hook;
   434     display_keysym_hook_data = data;
   435 }
   437 /***************** System mouse driver ****************/
   439 static struct keymap_entry *mouse_keymap[MAX_MOUSE_BUTTONS];
   440 static struct mouse_entry *mousehooks = NULL;
   441 static uint32_t mouse_x = -1, mouse_y = -1, mouse_buttons = 0;
   443 uint16_t mouse_resolve_keysym( struct input_driver *driver, const gchar *keysym )
   444 {
   445     if( strncasecmp( keysym, "Button", 6 ) == 0 ){
   446         unsigned long button = strtoul( keysym+6, NULL, 10 );
   447         if( button > MAX_MOUSE_BUTTONS ) {
   448             return 0;
   449         }
   450         return (uint16_t)button;
   451     }
   452     return 0;
   453 }
   455 gchar *mouse_get_keysym( struct input_driver *driver, uint16_t keycode )
   456 {
   457     return g_strdup_printf( "Button%d", (keycode) );
   458 }
   460 struct input_driver system_mouse_driver = { "Mouse", mouse_resolve_keysym, NULL, mouse_get_keysym, NULL };
   463 gboolean input_register_mouse_hook( gboolean relative, input_mouse_callback_t callback,
   464                                     void *data )
   465 {
   466     mouse_entry_t ent = malloc( sizeof( struct mouse_entry ) );
   467     assert( ent != NULL );
   468     ent->callback = callback;
   469     ent->data = data;
   470     ent->next = mousehooks;
   471     mousehooks = ent;
   472     return TRUE;
   473 }    
   475 void input_unregister_mouse_hook( input_mouse_callback_t callback, void *data )
   476 {
   477     mouse_entry_t ent = mousehooks;
   478     if( ent != NULL ) {
   479         if( ent->callback == callback && ent->data == data ) {
   480             mousehooks = mousehooks->next;
   481             free(ent);
   482             return;
   483         }
   484         while( ent->next != NULL ) {
   485             if( ent->next->callback == callback && ent->next->data == data ) {
   486                 mouse_entry_t next = ent->next;
   487                 ent->next = next->next;
   488                 free(next);
   489                 return;
   490             }
   491             ent = ent->next;
   492         }
   493     }
   494 }
   496 void input_event_run_mouse_hooks( uint32_t buttons, int32_t x, int32_t y, gboolean absolute )
   497 {
   498     mouse_entry_t ent = mousehooks;
   499     while( ent != NULL ) {
   500         ent->callback(ent->data, buttons, x, y, absolute);
   501         ent = ent->next;
   502     }
   503 }
   505 void input_event_mousedown( uint16_t button, int32_t x, int32_t y, gboolean absolute )
   506 {
   507     if( absolute ) {
   508         mouse_x = x;
   509         mouse_y = y;
   510     }
   511     mouse_buttons |= (1<<button);
   512     input_event_keydown( &system_mouse_driver, button+1, MAX_PRESSURE );
   513     input_event_run_mouse_hooks( mouse_buttons, x, y, absolute );
   514 }    
   516 void input_event_mouseup( uint16_t button, int32_t x, int32_t y, gboolean absolute )
   517 {
   518     if( absolute ) {
   519         mouse_x = x;
   520         mouse_y = y;
   521     }
   522     mouse_buttons &= ~(1<<button);
   523     input_event_keyup( &system_mouse_driver, button+1 );
   524     input_event_run_mouse_hooks( mouse_buttons, x, y, absolute );
   525 }
   527 void input_event_mousemove( int32_t x, int32_t y, gboolean absolute )
   528 {
   529     if( absolute ) {
   530         mouse_x = x;
   531         mouse_y = y;
   532     }
   533     input_event_run_mouse_hooks( mouse_buttons, x, y, absolute );
   534 }
   536 /************************ Main display driver *************************/
   538 void print_display_drivers( FILE *out )
   539 {
   540     int i;
   541     fprintf( out, "Available video drivers:\n" );
   542     for( i=0; display_driver_list[i] != NULL; i++ ) {
   543         fprintf( out, "  %-8s %s\n", display_driver_list[i]->name,
   544                 gettext(display_driver_list[i]->description) );
   545     }
   546 }
   548 display_driver_t get_display_driver_by_name( const char *name )
   549 {
   550     int i;
   551     if( name == NULL ) {
   552         return display_driver_list[0];
   553     }
   554     for( i=0; display_driver_list[i] != NULL; i++ ) {
   555         if( strcasecmp( display_driver_list[i]->name, name ) == 0 ) {
   556             return display_driver_list[i];
   557         }
   558     }
   560     return NULL;
   561 }
   564 gboolean display_set_driver( display_driver_t driver )
   565 {
   566     gboolean rv = TRUE;
   567     if( display_driver != NULL && display_driver->shutdown_driver != NULL ) 
   568         display_driver->shutdown_driver();
   570     display_driver = driver;
   571     if( driver->init_driver != NULL )
   572         rv = driver->init_driver();
   573     if( rv ) {
   574         input_register_device(&system_mouse_driver, MAX_MOUSE_BUTTONS);
   575     } else {
   576         display_driver = NULL;
   577     }
   578     return rv;
   579 }
   581 void display_set_focused( gboolean has_focus )
   582 {
   583     display_focused = has_focus;
   584 }
.