Search
lxdream.org :: lxdream/src/display.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/display.c
changeset 614:a2d239d4438a
prev608:4f588e52bce0
next615:38b69ec2f4c8
author nkeynes
date Mon Jan 28 02:38:09 2008 +0000 (16 years ago)
permissions -rw-r--r--
last change Bug #49: Joystick support work in progress
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 #endif
    31 					   &display_null_driver,
    32 					   NULL };
    34 /* Some explanation:
    35  *   The system has at least one "root" device representing the main display 
    36  * (which may be the null display). This device is part of the display_driver
    37  * and generates events with no input_driver. The root device has no id
    38  * as such (for the purposes of event names)
    39  *
    40  *   The system may also have one or more auxilliary devices which each have
    41  * an input_driver and an id (eg "JS0"). So the keysym "Return" is (de)coded by
    42  * the root device, and the keysym "JS0: Button0" is (de)coded by the JS0 input
    43  * device as "Button0".
    44  *
    45  *   For the moment, mice are handled specially, as they behave a little
    46  * differently from other devices (although this will probably change in the 
    47  * future.
    48  */
    51 typedef struct keymap_entry {
    52     input_key_callback_t callback;
    53     void *data;
    54     uint32_t value;
    55     struct keymap_entry *next; // allow chaining
    56 } *keymap_entry_t;
    58 typedef struct mouse_entry {
    59     gboolean relative;
    60     input_mouse_callback_t callback;
    61     void *data;
    62     struct mouse_entry *next;
    63 } *mouse_entry_t;
    65 typedef struct input_driver_entry {
    66     input_driver_t driver;
    67     uint16_t entry_count;
    68     struct keymap_entry *keymap[0];
    69 } *input_driver_entry_t;
    71 /**
    72  * Colour format information
    73  */
    74 struct colour_format colour_formats[] = {
    75     { GL_UNSIGNED_SHORT_1_5_5_5_REV, GL_BGRA, GL_RGB5_A1, 2 },
    76     { GL_UNSIGNED_SHORT_5_6_5, GL_RGB, GL_RGB5, 2 },
    77     { GL_UNSIGNED_SHORT_4_4_4_4_REV, GL_BGRA, GL_RGBA4, 2 },
    78     { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* YUV decoded to ARGB8888 */
    79     { GL_UNSIGNED_BYTE, GL_BGR, GL_RGB, 3 },
    80     { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 },
    81     { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* Index4 decoded */
    82     { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* Index8 decoded */
    83     { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 },
    84     { GL_UNSIGNED_BYTE, GL_RGB, GL_RGB, 3 },
    86 };
    88 /**
    89  * FIXME: make this more memory efficient
    90  */
    91 static struct keymap_entry *root_keymap[65535];
    92 static struct keymap_entry *keyhooks = NULL;
    93 static struct mouse_entry *mousehooks = NULL;
    94 static gboolean display_focused = TRUE;
    95 static GList *input_drivers= NULL;
    96 static display_keysym_callback_t display_keysym_hook = NULL;
    97 void *display_keysym_hook_data;
    99 gboolean input_register_device( input_driver_t driver, uint16_t max_keycode )
   100 {
   101     GList *ptr;
   102     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   103 	input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   104 	if( strcasecmp( entry->driver->id, driver->id ) == 0 ) {
   105 	    return FALSE;
   106 	}
   107     }
   109     input_driver_entry_t entry = g_malloc0( sizeof(struct input_driver_entry) + (sizeof(keymap_entry_t) * max_keycode) );
   110     entry->driver = driver;
   111     entry->entry_count = max_keycode;
   112     input_drivers = g_list_append( input_drivers, entry );
   113     return TRUE;
   114 }
   116 void input_unregister_device( input_driver_t driver )
   117 {
   118     GList *ptr;
   119     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   120 	input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   121 	if( entry->driver == driver ) {
   122 	    if( driver->destroy != NULL ) {
   123 		driver->destroy(driver);
   124 	    }
   125 	    input_drivers = g_list_remove(input_drivers, (gpointer)entry);
   126 	    g_free( entry );
   127 	    return;
   128 	}
   129     }
   130 }
   132 /**
   133  * Resolve the keysym and return a pointer to the keymap entry pointer
   134  * @return keymap pointer or NULL if the key was unresolved
   135  */
   136 static struct keymap_entry **input_entry_from_keysym( const gchar *keysym )
   137 {
   138     if( keysym == NULL || keysym[0] == 0 ) {
   139 	return NULL;
   140     }
   141     char **strv = g_strsplit(keysym,":",2);
   142     if( strv[1] == NULL ) {
   143 	/* root device */
   144 	if( display_driver == NULL || display_driver->resolve_keysym == NULL) {
   145 	    // Root device has no input handling
   146 	    g_strfreev(strv);
   147 	    return NULL;
   148 	}
   149 	uint16_t keycode = display_driver->resolve_keysym(g_strstrip(strv[0]));
   150 	g_strfreev(strv);
   151 	if( keycode == 0 ) {
   152 	    return NULL;
   153 	}
   154 	return &root_keymap[keycode-1];
   155     } else {
   156 	char *id = g_strstrip(strv[0]);
   157 	GList *ptr;
   158 	for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   159 	    input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   160 	    if( strcasecmp( entry->driver->id, id ) == 0 ) {
   161 		/* we have ze device */
   162 		if( entry->driver->resolve_keysym == NULL ) {
   163 		    g_strfreev(strv);
   164 		    return NULL;
   165 		} 
   166 		uint16_t keycode = entry->driver->resolve_keysym(entry->driver, g_strstrip(strv[1]));
   167 		g_strfreev(strv);
   168 		if( keycode == 0 || keycode > entry->entry_count ) {
   169 		    return NULL;
   170 		}
   171 		return &entry->keymap[keycode-1];
   172 	    }
   173 	}
   174 	g_strfreev(strv);
   175 	return NULL; // device not found
   176     }
   177 }
   179 static struct keymap_entry **input_entry_from_keycode( input_driver_t driver, uint16_t keycode )
   180 {
   181     GList *ptr;
   183     if( keycode == 0 ) {
   184 	return NULL;
   185     }
   187     if( driver == NULL ) {
   188 	return &root_keymap[keycode-1];
   189     }
   191     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   192 	input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   193 	if( entry->driver == driver ) {
   194 	    if( keycode > entry->entry_count ) {
   195 		return NULL;
   196 	    } else {
   197 		return &entry->keymap[keycode-1];
   198 	    }
   199 	}
   200     }
   201     return NULL;
   202 }
   204 static gchar *input_keysym_for_keycode( input_driver_t driver, uint16_t keycode )
   205 {
   206     if( keycode == 0 ) {
   207 	return NULL;
   208     }
   209     if( driver == NULL ) {
   210 	if( display_driver != NULL && display_driver->get_keysym_for_keycode != NULL ) {
   211 	    return display_driver->get_keysym_for_keycode(keycode);
   212 	}
   213     } else if( driver->get_keysym_for_keycode ) {
   214 	gchar *sym = driver->get_keysym_for_keycode(driver,keycode);
   215 	if( sym != NULL ) {
   216 	    gchar *result = g_strdup_printf( "%s: %s", driver->id, sym );
   217 	    g_free(sym);
   218 	    return result;
   219 	}
   220     }
   221     return NULL;
   222 }
   225 gboolean input_register_key( const gchar *keysym, input_key_callback_t callback,
   226 			     void *data, uint32_t value )
   227 {
   228     if( keysym == NULL ) {
   229 	return FALSE;
   230     }
   231     int keys = 0;
   232     gchar **strv = g_strsplit(keysym, ",", 16);
   233     gchar **s = strv;
   234     while( *s != NULL ) {
   235 	keymap_entry_t *entryp = input_entry_from_keysym(*s);
   236 	if( entryp != NULL ) {
   237 	    *entryp = g_malloc0(sizeof(struct keymap_entry));
   238 	    (*entryp)->callback = callback;
   239 	    (*entryp)->data = data;
   240 	    (*entryp)->value = value;
   241 	    keys++;
   242 	}
   243 	s++;
   244     }
   245     g_strfreev(strv);
   246     return keys != 0;
   247 }
   249 void input_unregister_key( const gchar *keysym, input_key_callback_t callback,
   250 			   void *data, uint32_t value )
   251 {
   252     if( keysym == NULL ) {
   253 	return;
   254     }
   256     gchar **strv = g_strsplit(keysym, ",", 16);
   257     gchar **s = strv;
   258     while( *s != NULL ) {
   259 	keymap_entry_t *entryp = input_entry_from_keysym(*s);
   260 	if( entryp != NULL && *entryp != NULL && (*entryp)->callback == callback &&
   261 	    (*entryp)->data == data && (*entryp)->value == value ) {
   262 	    g_free( *entryp );
   263 	    *entryp = NULL;
   264 	}
   265 	s++;
   266     }
   267     g_strfreev(strv);
   268 }
   270 gboolean input_register_hook( input_key_callback_t callback,
   271 			      void *data )
   272 {
   273     keymap_entry_t key = malloc( sizeof( struct keymap_entry ) );
   274     assert( key != NULL );
   275     key->callback = callback;
   276     key->data = data;
   277     key->next = keyhooks;
   278     keyhooks = key;
   279     return TRUE;
   280 }
   282 void input_unregister_hook( input_key_callback_t callback,
   283 			    void *data )
   284 {
   285     keymap_entry_t key = keyhooks;
   286     if( key != NULL ) {
   287 	keymap_entry_t next = key->next;
   288 	if( key->callback == callback && key->data == data ) {
   289 	    free(key);
   290 	    keyhooks = next;
   291 	    return;
   292 	}
   293 	while( next != NULL ) {
   294 	    if( next->callback == callback && next->data == data ) {
   295 		key->next = next->next;
   296 		free(next);
   297 	    }
   298 	}
   299     }
   300 }
   302 gboolean input_register_mouse_hook( gboolean relative, input_mouse_callback_t callback,
   303 				void *data )
   304 {
   305     mouse_entry_t ent = malloc( sizeof( struct mouse_entry ) );
   306     assert( ent != NULL );
   307     ent->callback = callback;
   308     ent->data = data;
   309     ent->next = mousehooks;
   310     mousehooks = ent;
   311     return TRUE;
   312 }    
   314 void input_unregister_mouse_hook( input_mouse_callback_t callback, void *data )
   315 {
   316     mouse_entry_t ent = mousehooks;
   317     if( ent != NULL ) {
   318 	mouse_entry_t next = ent->next;
   319 	if( ent->callback == callback && ent->data == data ) {
   320 	    free(ent);
   321 	    mousehooks = next;
   322 	    return;
   323 	}
   324 	while( next != NULL ) {
   325 	    if( next->callback == callback && next->data == data ) {
   326 		ent->next = next->next;
   327 		free(next);
   328 	    }
   329 	}
   330     }
   331 }
   333 void input_event_mouse( uint32_t buttons, int32_t x, int32_t y )
   334 {
   335     mouse_entry_t ent = mousehooks;
   336     while( ent != NULL ) {
   337 	ent->callback(ent->data, buttons, x, y);
   338 	ent = ent->next;
   339     }
   340 }
   342 gboolean input_is_key_valid( const gchar *keysym )
   343 {
   344     keymap_entry_t *ptr = input_entry_from_keysym(keysym);
   345     return ptr != NULL;
   346 }
   348 gboolean input_is_key_registered( const gchar *keysym )
   349 {
   350     keymap_entry_t *ptr = input_entry_from_keysym(keysym);
   351     return ptr != NULL && *ptr != NULL;
   352 }
   354 void input_event_keydown( input_driver_t driver, uint16_t keycode, uint32_t pressure )
   355 {
   356     if( display_focused ) {
   357 	keymap_entry_t *entryp = input_entry_from_keycode(driver,keycode);
   358 	if( entryp != NULL && *entryp != NULL ) {
   359 	    (*entryp)->callback( (*entryp)->data, (*entryp)->value, pressure, TRUE );
   360 	}
   361 	keymap_entry_t key = keyhooks;
   362 	while( key != NULL ) {
   363 	    key->callback( key->data, keycode, pressure, TRUE );
   364 	    key = key->next;
   365 	}
   366     }
   367     if( display_keysym_hook != NULL ) {
   368 	gchar *sym = input_keysym_for_keycode( driver, keycode );
   369 	if( sym != NULL ) {
   370 	    display_keysym_hook(display_keysym_hook_data, sym);
   371 	    g_free(sym);
   372 	}
   373     }
   374 }
   376 void input_event_keyup( 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 && *entryp != NULL ) {
   381 	    (*entryp)->callback( (*entryp)->data, (*entryp)->value, pressure, FALSE );
   382 	}
   384 	keymap_entry_t key = keyhooks;
   385 	while( key != NULL ) {
   386 	    key->callback( key->data, keycode, pressure, FALSE );
   387 	    key = key->next;
   388 	}
   389     }
   390 }
   392 uint16_t input_keycode_to_dckeysym( uint16_t keycode )
   393 {
   394     return display_driver->convert_to_dckeysym(keycode);
   395 }
   397 display_driver_t get_display_driver_by_name( const char *name )
   398 {
   399     int i;
   400     if( name == NULL ) {
   401 	return display_driver_list[0];
   402     }
   403     for( i=0; display_driver_list[i] != NULL; i++ ) {
   404 	if( strcasecmp( display_driver_list[i]->name, name ) == 0 ) {
   405 	    return display_driver_list[i];
   406 	}
   407     }
   409     return NULL;
   410 }
   413 gboolean display_set_driver( display_driver_t driver )
   414 {
   415     gboolean rv = TRUE;
   416     if( display_driver != NULL && display_driver->shutdown_driver != NULL ) 
   417 	display_driver->shutdown_driver();
   419     display_driver = driver;
   420     if( driver->init_driver != NULL )
   421 	rv = driver->init_driver();
   422     if( !rv ) {
   423 	display_driver = NULL;
   424     }
   425     return rv;
   426 }
   428 void display_set_focused( gboolean has_focus )
   429 {
   430     display_focused = has_focus;
   431 }
   433 void input_set_keysym_hook( display_keysym_callback_t hook, void *data )
   434 {
   435     display_keysym_hook = hook;
   436     display_keysym_hook_data = data;
   437 }
.