Search
lxdream.org :: lxdream/src/display.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/display.c
changeset 627:c218b062a843
prev615:38b69ec2f4c8
next681:1755a126b109
author nkeynes
date Fri Feb 08 00:58:41 2008 +0000 (16 years ago)
permissions -rw-r--r--
last change Fix broken kbd/mouse hook release
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 gboolean input_has_device( const gchar *id )
   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( strcasecmp(entry->driver->id, id) == 0 ) {
   122 	    return TRUE;
   123 	}
   124     }
   125     return FALSE;
   126 }
   129 void input_unregister_device( input_driver_t driver )
   130 {
   131     GList *ptr;
   132     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   133 	input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   134 	if( entry->driver == driver ) {
   135 	    if( driver->destroy != NULL ) {
   136 		driver->destroy(driver);
   137 	    }
   138 	    input_drivers = g_list_remove(input_drivers, (gpointer)entry);
   139 	    g_free( entry );
   140 	    return;
   141 	}
   142     }
   143 }
   145 /**
   146  * Resolve the keysym and return a pointer to the keymap entry pointer
   147  * @return keymap pointer or NULL if the key was unresolved
   148  */
   149 static struct keymap_entry **input_entry_from_keysym( const gchar *keysym )
   150 {
   151     if( keysym == NULL || keysym[0] == 0 ) {
   152 	return NULL;
   153     }
   154     char **strv = g_strsplit(keysym,":",2);
   155     if( strv[1] == NULL ) {
   156 	/* root device */
   157 	if( display_driver == NULL || display_driver->resolve_keysym == NULL) {
   158 	    // Root device has no input handling
   159 	    g_strfreev(strv);
   160 	    return NULL;
   161 	}
   162 	uint16_t keycode = display_driver->resolve_keysym(g_strstrip(strv[0]));
   163 	g_strfreev(strv);
   164 	if( keycode == 0 ) {
   165 	    return NULL;
   166 	}
   167 	return &root_keymap[keycode-1];
   168     } else {
   169 	char *id = g_strstrip(strv[0]);
   170 	GList *ptr;
   171 	for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   172 	    input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   173 	    if( strcasecmp( entry->driver->id, id ) == 0 ) {
   174 		/* we have ze device */
   175 		if( entry->driver->resolve_keysym == NULL ) {
   176 		    g_strfreev(strv);
   177 		    return NULL;
   178 		} 
   179 		uint16_t keycode = entry->driver->resolve_keysym(entry->driver, g_strstrip(strv[1]));
   180 		g_strfreev(strv);
   181 		if( keycode == 0 || keycode > entry->entry_count ) {
   182 		    return NULL;
   183 		}
   184 		return &entry->keymap[keycode-1];
   185 	    }
   186 	}
   187 	g_strfreev(strv);
   188 	return NULL; // device not found
   189     }
   190 }
   192 static struct keymap_entry **input_entry_from_keycode( input_driver_t driver, uint16_t keycode )
   193 {
   194     GList *ptr;
   196     if( keycode == 0 ) {
   197 	return NULL;
   198     }
   200     if( driver == NULL ) {
   201 	return &root_keymap[keycode-1];
   202     }
   204     for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) {
   205 	input_driver_entry_t entry = (input_driver_entry_t)ptr->data;
   206 	if( entry->driver == driver ) {
   207 	    if( keycode > entry->entry_count ) {
   208 		return NULL;
   209 	    } else {
   210 		return &entry->keymap[keycode-1];
   211 	    }
   212 	}
   213     }
   214     return NULL;
   215 }
   217 static gchar *input_keysym_for_keycode( input_driver_t driver, uint16_t keycode )
   218 {
   219     if( keycode == 0 ) {
   220 	return NULL;
   221     }
   222     if( driver == NULL ) {
   223 	if( display_driver != NULL && display_driver->get_keysym_for_keycode != NULL ) {
   224 	    return display_driver->get_keysym_for_keycode(keycode);
   225 	}
   226     } else if( driver->get_keysym_for_keycode ) {
   227 	gchar *sym = driver->get_keysym_for_keycode(driver,keycode);
   228 	if( sym != NULL ) {
   229 	    gchar *result = g_strdup_printf( "%s: %s", driver->id, sym );
   230 	    g_free(sym);
   231 	    return result;
   232 	}
   233     }
   234     return NULL;
   235 }
   238 gboolean input_register_key( const gchar *keysym, input_key_callback_t callback,
   239 			     void *data, uint32_t value )
   240 {
   241     if( keysym == NULL ) {
   242 	return FALSE;
   243     }
   244     int keys = 0;
   245     gchar **strv = g_strsplit(keysym, ",", 16);
   246     gchar **s = strv;
   247     while( *s != NULL ) {
   248 	keymap_entry_t *entryp = input_entry_from_keysym(*s);
   249 	if( entryp != NULL ) {
   250 	    *entryp = g_malloc0(sizeof(struct keymap_entry));
   251 	    (*entryp)->callback = callback;
   252 	    (*entryp)->data = data;
   253 	    (*entryp)->value = value;
   254 	    keys++;
   255 	}
   256 	s++;
   257     }
   258     g_strfreev(strv);
   259     return keys != 0;
   260 }
   262 void input_unregister_key( const gchar *keysym, input_key_callback_t callback,
   263 			   void *data, uint32_t value )
   264 {
   265     if( keysym == NULL ) {
   266 	return;
   267     }
   269     gchar **strv = g_strsplit(keysym, ",", 16);
   270     gchar **s = strv;
   271     while( *s != NULL ) {
   272 	keymap_entry_t *entryp = input_entry_from_keysym(*s);
   273 	if( entryp != NULL && *entryp != NULL && (*entryp)->callback == callback &&
   274 	    (*entryp)->data == data && (*entryp)->value == value ) {
   275 	    g_free( *entryp );
   276 	    *entryp = NULL;
   277 	}
   278 	s++;
   279     }
   280     g_strfreev(strv);
   281 }
   283 gboolean input_register_hook( input_key_callback_t callback,
   284 			      void *data )
   285 {
   286     keymap_entry_t key = malloc( sizeof( struct keymap_entry ) );
   287     assert( key != NULL );
   288     key->callback = callback;
   289     key->data = data;
   290     key->next = keyhooks;
   291     keyhooks = key;
   292     return TRUE;
   293 }
   295 void input_unregister_hook( input_key_callback_t callback,
   296 			    void *data )
   297 {
   298     keymap_entry_t key = keyhooks;
   299     if( key != NULL ) {
   300 	if( key->callback == callback && key->data == data ) {
   301 	    keyhooks = keyhooks->next;
   302 	    free(key);
   303 	    return;
   304 	}
   305 	while( key->next != NULL ) {
   306 	    if( key->next->callback == callback && key->next->data == data ) {
   307                 keymap_entry_t next = key->next;
   308 		key->next = next->next;
   309 		free(next);
   310 		return;
   311 	    }
   312 	    key = key->next;
   313 	}
   314     }
   315 }
   317 gboolean input_register_mouse_hook( gboolean relative, input_mouse_callback_t callback,
   318 				void *data )
   319 {
   320     mouse_entry_t ent = malloc( sizeof( struct mouse_entry ) );
   321     assert( ent != NULL );
   322     ent->callback = callback;
   323     ent->data = data;
   324     ent->next = mousehooks;
   325     mousehooks = ent;
   326     return TRUE;
   327 }    
   329 void input_unregister_mouse_hook( input_mouse_callback_t callback, void *data )
   330 {
   331     mouse_entry_t ent = mousehooks;
   332     if( ent != NULL ) {
   333 	if( ent->callback == callback && ent->data == data ) {
   334 	    mousehooks = mousehooks->next;
   335 	    free(ent);
   336 	    return;
   337 	}
   338 	while( ent->next != NULL ) {
   339 	    if( ent->next->callback == callback && ent->next->data == data ) {
   340                 mouse_entry_t next = ent->next;
   341 		ent->next = next->next;
   342 		free(next);
   343 		return;
   344 	    }
   345 	    ent = ent->next;
   346 	}
   347     }
   348 }
   350 void input_event_mouse( uint32_t buttons, int32_t x, int32_t y )
   351 {
   352     mouse_entry_t ent = mousehooks;
   353     while( ent != NULL ) {
   354 	ent->callback(ent->data, buttons, x, y);
   355 	ent = ent->next;
   356     }
   357 }
   359 gboolean input_is_key_valid( const gchar *keysym )
   360 {
   361     keymap_entry_t *ptr = input_entry_from_keysym(keysym);
   362     return ptr != NULL;
   363 }
   365 gboolean input_is_key_registered( const gchar *keysym )
   366 {
   367     keymap_entry_t *ptr = input_entry_from_keysym(keysym);
   368     return ptr != NULL && *ptr != NULL;
   369 }
   371 void input_event_keydown( input_driver_t driver, uint16_t keycode, uint32_t pressure )
   372 {
   373     if( display_focused ) {
   374 	keymap_entry_t *entryp = input_entry_from_keycode(driver,keycode);
   375 	if( entryp != NULL && *entryp != NULL ) {
   376 	    (*entryp)->callback( (*entryp)->data, (*entryp)->value, pressure, TRUE );
   377 	}
   378 	keymap_entry_t key = keyhooks;
   379 	while( key != NULL ) {
   380 	    key->callback( key->data, keycode, pressure, TRUE );
   381 	    key = key->next;
   382 	}
   383     }
   384     if( display_keysym_hook != NULL ) {
   385 	gchar *sym = input_keysym_for_keycode( driver, keycode );
   386 	if( sym != NULL ) {
   387 	    display_keysym_hook(display_keysym_hook_data, sym);
   388 	    g_free(sym);
   389 	}
   390     }
   391 }
   393 void input_event_keyup( input_driver_t driver, uint16_t keycode, uint32_t pressure )
   394 {
   395     if( display_focused ) {
   396 	keymap_entry_t *entryp = input_entry_from_keycode(driver,keycode);
   397 	if( entryp != NULL && *entryp != NULL ) {
   398 	    (*entryp)->callback( (*entryp)->data, (*entryp)->value, pressure, FALSE );
   399 	}
   401 	keymap_entry_t key = keyhooks;
   402 	while( key != NULL ) {
   403 	    key->callback( key->data, keycode, pressure, FALSE );
   404 	    key = key->next;
   405 	}
   406     }
   407 }
   409 uint16_t input_keycode_to_dckeysym( uint16_t keycode )
   410 {
   411     return display_driver->convert_to_dckeysym(keycode);
   412 }
   414 display_driver_t get_display_driver_by_name( const char *name )
   415 {
   416     int i;
   417     if( name == NULL ) {
   418 	return display_driver_list[0];
   419     }
   420     for( i=0; display_driver_list[i] != NULL; i++ ) {
   421 	if( strcasecmp( display_driver_list[i]->name, name ) == 0 ) {
   422 	    return display_driver_list[i];
   423 	}
   424     }
   426     return NULL;
   427 }
   430 gboolean display_set_driver( display_driver_t driver )
   431 {
   432     gboolean rv = TRUE;
   433     if( display_driver != NULL && display_driver->shutdown_driver != NULL ) 
   434 	display_driver->shutdown_driver();
   436     display_driver = driver;
   437     if( driver->init_driver != NULL )
   438 	rv = driver->init_driver();
   439     if( !rv ) {
   440 	display_driver = NULL;
   441     }
   442     return rv;
   443 }
   445 void display_set_focused( gboolean has_focus )
   446 {
   447     display_focused = has_focus;
   448 }
   450 void input_set_keysym_hook( display_keysym_callback_t hook, void *data )
   451 {
   452     display_keysym_hook = hook;
   453     display_keysym_hook_data = data;
   454 }
.