Search
lxdream.org :: lxdream/src/display.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/display.c
changeset 700:4650d0c7f6f9
prev681:1755a126b109
next736:a02d1475ccfd
author nkeynes
date Sun Jun 22 06:49:00 2008 +0000 (12 years ago)
permissions -rw-r--r--
last change Big cleanup of the command-line options
Add an actual manpage (*gasp*)
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 struct mouse_entry *mousehooks = NULL;
    98 static gboolean display_focused = TRUE;
    99 static GList *input_drivers= NULL;
   100 static display_keysym_callback_t display_keysym_hook = NULL;
   101 void *display_keysym_hook_data;
   103 gboolean input_register_device( input_driver_t driver, uint16_t max_keycode )
   104 {
   105     GList *ptr;
   106     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   107 	input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   108 	if( strcasecmp( entry->driver->id, driver->id ) == 0 ) {
   109 	    return FALSE;
   110 	}
   111     }
   113     input_driver_entry_t entry = g_malloc0( sizeof(struct input_driver_entry) + (sizeof(keymap_entry_t) * max_keycode) );
   114     entry->driver = driver;
   115     entry->entry_count = max_keycode;
   116     input_drivers = g_list_append( input_drivers, entry );
   117     return TRUE;
   118 }
   120 gboolean input_has_device( const gchar *id )
   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, id) == 0 ) {
   126 	    return TRUE;
   127 	}
   128     }
   129     return FALSE;
   130 }
   133 void input_unregister_device( input_driver_t driver )
   134 {
   135     GList *ptr;
   136     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   137 	input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   138 	if( entry->driver == driver ) {
   139 	    if( driver->destroy != NULL ) {
   140 		driver->destroy(driver);
   141 	    }
   142 	    input_drivers = g_list_remove(input_drivers, (gpointer)entry);
   143 	    g_free( entry );
   144 	    return;
   145 	}
   146     }
   147 }
   149 /**
   150  * Resolve the keysym and return a pointer to the keymap entry pointer
   151  * @return keymap pointer or NULL if the key was unresolved
   152  */
   153 static struct keymap_entry **input_entry_from_keysym( const gchar *keysym )
   154 {
   155     if( keysym == NULL || keysym[0] == 0 ) {
   156 	return NULL;
   157     }
   158     char **strv = g_strsplit(keysym,":",2);
   159     if( strv[1] == NULL ) {
   160 	/* root device */
   161 	if( display_driver == NULL || display_driver->resolve_keysym == NULL) {
   162 	    // Root device has no input handling
   163 	    g_strfreev(strv);
   164 	    return NULL;
   165 	}
   166 	uint16_t keycode = display_driver->resolve_keysym(g_strstrip(strv[0]));
   167 	g_strfreev(strv);
   168 	if( keycode == 0 ) {
   169 	    return NULL;
   170 	}
   171 	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 static gchar *input_keysym_for_keycode( 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 	    *entryp = g_malloc0(sizeof(struct keymap_entry));
   255 	    (*entryp)->callback = callback;
   256 	    (*entryp)->data = data;
   257 	    (*entryp)->value = value;
   258 	    keys++;
   259 	}
   260 	s++;
   261     }
   262     g_strfreev(strv);
   263     return keys != 0;
   264 }
   266 void input_unregister_key( const gchar *keysym, input_key_callback_t callback,
   267 			   void *data, uint32_t value )
   268 {
   269     if( keysym == NULL ) {
   270 	return;
   271     }
   273     gchar **strv = g_strsplit(keysym, ",", 16);
   274     gchar **s = strv;
   275     while( *s != NULL ) {
   276 	keymap_entry_t *entryp = input_entry_from_keysym(*s);
   277 	if( entryp != NULL && *entryp != NULL && (*entryp)->callback == callback &&
   278 	    (*entryp)->data == data && (*entryp)->value == value ) {
   279 	    g_free( *entryp );
   280 	    *entryp = NULL;
   281 	}
   282 	s++;
   283     }
   284     g_strfreev(strv);
   285 }
   287 gboolean input_register_hook( input_key_callback_t callback,
   288 			      void *data )
   289 {
   290     keymap_entry_t key = malloc( sizeof( struct keymap_entry ) );
   291     assert( key != NULL );
   292     key->callback = callback;
   293     key->data = data;
   294     key->next = keyhooks;
   295     keyhooks = key;
   296     return TRUE;
   297 }
   299 void input_unregister_hook( input_key_callback_t callback,
   300 			    void *data )
   301 {
   302     keymap_entry_t key = keyhooks;
   303     if( key != NULL ) {
   304 	if( key->callback == callback && key->data == data ) {
   305 	    keyhooks = keyhooks->next;
   306 	    free(key);
   307 	    return;
   308 	}
   309 	while( key->next != NULL ) {
   310 	    if( key->next->callback == callback && key->next->data == data ) {
   311                 keymap_entry_t next = key->next;
   312 		key->next = next->next;
   313 		free(next);
   314 		return;
   315 	    }
   316 	    key = key->next;
   317 	}
   318     }
   319 }
   321 gboolean input_register_mouse_hook( gboolean relative, input_mouse_callback_t callback,
   322 				void *data )
   323 {
   324     mouse_entry_t ent = malloc( sizeof( struct mouse_entry ) );
   325     assert( ent != NULL );
   326     ent->callback = callback;
   327     ent->data = data;
   328     ent->next = mousehooks;
   329     mousehooks = ent;
   330     return TRUE;
   331 }    
   333 void input_unregister_mouse_hook( input_mouse_callback_t callback, void *data )
   334 {
   335     mouse_entry_t ent = mousehooks;
   336     if( ent != NULL ) {
   337 	if( ent->callback == callback && ent->data == data ) {
   338 	    mousehooks = mousehooks->next;
   339 	    free(ent);
   340 	    return;
   341 	}
   342 	while( ent->next != NULL ) {
   343 	    if( ent->next->callback == callback && ent->next->data == data ) {
   344                 mouse_entry_t next = ent->next;
   345 		ent->next = next->next;
   346 		free(next);
   347 		return;
   348 	    }
   349 	    ent = ent->next;
   350 	}
   351     }
   352 }
   354 void input_event_mouse( uint32_t buttons, int32_t x, int32_t y )
   355 {
   356     mouse_entry_t ent = mousehooks;
   357     while( ent != NULL ) {
   358 	ent->callback(ent->data, buttons, x, y);
   359 	ent = ent->next;
   360     }
   361 }
   363 gboolean input_is_key_valid( const gchar *keysym )
   364 {
   365     keymap_entry_t *ptr = input_entry_from_keysym(keysym);
   366     return ptr != NULL;
   367 }
   369 gboolean input_is_key_registered( const gchar *keysym )
   370 {
   371     keymap_entry_t *ptr = input_entry_from_keysym(keysym);
   372     return ptr != NULL && *ptr != NULL;
   373 }
   375 void input_event_keydown( input_driver_t driver, uint16_t keycode, uint32_t pressure )
   376 {
   377     if( display_focused ) {
   378 	keymap_entry_t *entryp = input_entry_from_keycode(driver,keycode);
   379 	if( entryp != NULL && *entryp != NULL ) {
   380 	    (*entryp)->callback( (*entryp)->data, (*entryp)->value, pressure, TRUE );
   381 	}
   382 	keymap_entry_t key = keyhooks;
   383 	while( key != NULL ) {
   384 	    key->callback( key->data, keycode, pressure, TRUE );
   385 	    key = key->next;
   386 	}
   387     }
   388     if( display_keysym_hook != NULL ) {
   389 	gchar *sym = input_keysym_for_keycode( driver, keycode );
   390 	if( sym != NULL ) {
   391 	    display_keysym_hook(display_keysym_hook_data, sym);
   392 	    g_free(sym);
   393 	}
   394     }
   395 }
   397 void input_event_keyup( input_driver_t driver, uint16_t keycode, uint32_t pressure )
   398 {
   399     if( display_focused ) {
   400 	keymap_entry_t *entryp = input_entry_from_keycode(driver,keycode);
   401 	if( entryp != NULL && *entryp != NULL ) {
   402 	    (*entryp)->callback( (*entryp)->data, (*entryp)->value, pressure, FALSE );
   403 	}
   405 	keymap_entry_t key = keyhooks;
   406 	while( key != NULL ) {
   407 	    key->callback( key->data, keycode, pressure, FALSE );
   408 	    key = key->next;
   409 	}
   410     }
   411 }
   413 uint16_t input_keycode_to_dckeysym( uint16_t keycode )
   414 {
   415     return display_driver->convert_to_dckeysym(keycode);
   416 }
   418 void print_display_drivers( FILE *out )
   419 {
   420     int i;
   421     fprintf( out, "Available video drivers:\n" );
   422     for( i=0; display_driver_list[i] != NULL; i++ ) {
   423         fprintf( out, "  %-8s %s\n", display_driver_list[i]->name,
   424                  gettext(display_driver_list[i]->description) );
   425     }
   426 }
   428 display_driver_t get_display_driver_by_name( const char *name )
   429 {
   430     int i;
   431     if( name == NULL ) {
   432 	return display_driver_list[0];
   433     }
   434     for( i=0; display_driver_list[i] != NULL; i++ ) {
   435 	if( strcasecmp( display_driver_list[i]->name, name ) == 0 ) {
   436 	    return display_driver_list[i];
   437 	}
   438     }
   440     return NULL;
   441 }
   444 gboolean display_set_driver( display_driver_t driver )
   445 {
   446     gboolean rv = TRUE;
   447     if( display_driver != NULL && display_driver->shutdown_driver != NULL ) 
   448 	display_driver->shutdown_driver();
   450     display_driver = driver;
   451     if( driver->init_driver != NULL )
   452 	rv = driver->init_driver();
   453     if( !rv ) {
   454 	display_driver = NULL;
   455     }
   456     return rv;
   457 }
   459 void display_set_focused( gboolean has_focus )
   460 {
   461     display_focused = has_focus;
   462 }
   464 void input_set_keysym_hook( display_keysym_callback_t hook, void *data )
   465 {
   466     display_keysym_hook = hook;
   467     display_keysym_hook_data = data;
   468 }
.