nkeynes@144: /** nkeynes@561: * $Id$ nkeynes@144: * nkeynes@144: * Generic support for keyboard and other input sources. The active display nkeynes@144: * driver is expected to deliver events here, where they're translated and nkeynes@144: * passed to the appropriate dreamcast controllers (if any). nkeynes@144: * nkeynes@144: * Copyright (c) 2005 Nathan Keynes. nkeynes@144: * nkeynes@144: * This program is free software; you can redistribute it and/or modify nkeynes@144: * it under the terms of the GNU General Public License as published by nkeynes@144: * the Free Software Foundation; either version 2 of the License, or nkeynes@144: * (at your option) any later version. nkeynes@144: * nkeynes@144: * This program is distributed in the hope that it will be useful, nkeynes@144: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@144: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@144: * GNU General Public License for more details. nkeynes@144: */ nkeynes@144: nkeynes@144: #include nkeynes@144: #include nkeynes@144: #include "dream.h" nkeynes@144: #include "display.h" nkeynes@431: #include "pvr2/pvr2.h" nkeynes@144: nkeynes@681: display_driver_t display_driver_list[] = { nkeynes@541: #ifdef HAVE_GTK nkeynes@736: &display_gtk_driver, nkeynes@681: #else nkeynes@681: #ifdef HAVE_COCOA nkeynes@736: &display_osx_driver, nkeynes@541: #endif nkeynes@681: #endif nkeynes@736: &display_null_driver, nkeynes@736: NULL }; nkeynes@531: nkeynes@614: /* Some explanation: nkeynes@614: * The system has at least one "root" device representing the main display nkeynes@614: * (which may be the null display). This device is part of the display_driver nkeynes@614: * and generates events with no input_driver. The root device has no id nkeynes@614: * as such (for the purposes of event names) nkeynes@614: * nkeynes@614: * The system may also have one or more auxilliary devices which each have nkeynes@614: * an input_driver and an id (eg "JS0"). So the keysym "Return" is (de)coded by nkeynes@614: * the root device, and the keysym "JS0: Button0" is (de)coded by the JS0 input nkeynes@614: * device as "Button0". nkeynes@614: * nkeynes@614: * For the moment, mice are handled specially, as they behave a little nkeynes@614: * differently from other devices (although this will probably change in the nkeynes@614: * future. nkeynes@614: */ nkeynes@614: nkeynes@614: nkeynes@144: typedef struct keymap_entry { nkeynes@144: input_key_callback_t callback; nkeynes@144: void *data; nkeynes@144: uint32_t value; nkeynes@608: struct keymap_entry *next; // allow chaining nkeynes@144: } *keymap_entry_t; nkeynes@144: nkeynes@608: typedef struct mouse_entry { nkeynes@608: gboolean relative; nkeynes@608: input_mouse_callback_t callback; nkeynes@608: void *data; nkeynes@608: struct mouse_entry *next; nkeynes@608: } *mouse_entry_t; nkeynes@608: nkeynes@614: typedef struct input_driver_entry { nkeynes@614: input_driver_t driver; nkeynes@614: uint16_t entry_count; nkeynes@614: struct keymap_entry *keymap[0]; nkeynes@614: } *input_driver_entry_t; nkeynes@614: nkeynes@144: /** nkeynes@327: * Colour format information nkeynes@327: */ nkeynes@327: struct colour_format colour_formats[] = { nkeynes@736: { GL_UNSIGNED_SHORT_1_5_5_5_REV, GL_BGRA, GL_RGB5_A1, 2 }, nkeynes@736: { GL_UNSIGNED_SHORT_5_6_5, GL_RGB, GL_RGB5, 2 }, nkeynes@736: { GL_UNSIGNED_SHORT_4_4_4_4_REV, GL_BGRA, GL_RGBA4, 2 }, nkeynes@736: { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* YUV decoded to ARGB8888 */ nkeynes@736: { GL_UNSIGNED_BYTE, GL_BGR, GL_RGB, 3 }, nkeynes@736: { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, nkeynes@736: { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* Index4 decoded */ nkeynes@736: { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, /* Index8 decoded */ nkeynes@736: { GL_UNSIGNED_BYTE, GL_BGRA, GL_RGBA8, 4 }, nkeynes@736: { GL_UNSIGNED_BYTE, GL_RGB, GL_RGB, 3 }, nkeynes@736: nkeynes@327: }; nkeynes@327: nkeynes@327: /** nkeynes@144: * FIXME: make this more memory efficient nkeynes@144: */ nkeynes@614: static struct keymap_entry *root_keymap[65535]; nkeynes@614: static struct keymap_entry *keyhooks = NULL; nkeynes@614: static gboolean display_focused = TRUE; nkeynes@614: static GList *input_drivers= NULL; nkeynes@614: static display_keysym_callback_t display_keysym_hook = NULL; nkeynes@614: void *display_keysym_hook_data; nkeynes@144: nkeynes@614: gboolean input_register_device( input_driver_t driver, uint16_t max_keycode ) nkeynes@144: { nkeynes@614: GList *ptr; nkeynes@614: for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) { nkeynes@736: input_driver_entry_t entry = (input_driver_entry_t)ptr->data; nkeynes@736: if( strcasecmp( entry->driver->id, driver->id ) == 0 ) { nkeynes@736: return FALSE; nkeynes@736: } nkeynes@144: } nkeynes@614: nkeynes@614: input_driver_entry_t entry = g_malloc0( sizeof(struct input_driver_entry) + (sizeof(keymap_entry_t) * max_keycode) ); nkeynes@614: entry->driver = driver; nkeynes@614: entry->entry_count = max_keycode; nkeynes@614: input_drivers = g_list_append( input_drivers, entry ); nkeynes@614: return TRUE; nkeynes@144: } nkeynes@144: nkeynes@615: gboolean input_has_device( const gchar *id ) nkeynes@615: { nkeynes@615: GList *ptr; nkeynes@615: for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) { nkeynes@736: input_driver_entry_t entry = (input_driver_entry_t)ptr->data; nkeynes@736: if( strcasecmp(entry->driver->id, id) == 0 ) { nkeynes@736: return TRUE; nkeynes@736: } nkeynes@615: } nkeynes@615: return FALSE; nkeynes@615: } nkeynes@615: nkeynes@615: nkeynes@614: void input_unregister_device( input_driver_t driver ) nkeynes@144: { nkeynes@614: GList *ptr; nkeynes@614: for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) { nkeynes@736: input_driver_entry_t entry = (input_driver_entry_t)ptr->data; nkeynes@736: if( entry->driver == driver ) { nkeynes@736: if( driver->destroy != NULL ) { nkeynes@736: driver->destroy(driver); nkeynes@736: } nkeynes@736: input_drivers = g_list_remove(input_drivers, (gpointer)entry); nkeynes@736: g_free( entry ); nkeynes@736: return; nkeynes@736: } nkeynes@144: } nkeynes@144: } nkeynes@144: nkeynes@614: /** nkeynes@614: * Resolve the keysym and return a pointer to the keymap entry pointer nkeynes@614: * @return keymap pointer or NULL if the key was unresolved nkeynes@614: */ nkeynes@614: static struct keymap_entry **input_entry_from_keysym( const gchar *keysym ) nkeynes@144: { nkeynes@614: if( keysym == NULL || keysym[0] == 0 ) { nkeynes@736: return NULL; nkeynes@614: } nkeynes@614: char **strv = g_strsplit(keysym,":",2); nkeynes@614: if( strv[1] == NULL ) { nkeynes@736: /* root device */ nkeynes@736: if( display_driver == NULL || display_driver->resolve_keysym == NULL) { nkeynes@736: // Root device has no input handling nkeynes@736: g_strfreev(strv); nkeynes@736: return NULL; nkeynes@736: } nkeynes@736: uint16_t keycode = display_driver->resolve_keysym(g_strstrip(strv[0])); nkeynes@736: g_strfreev(strv); nkeynes@736: if( keycode == 0 ) { nkeynes@736: return NULL; nkeynes@736: } nkeynes@736: return &root_keymap[keycode-1]; nkeynes@849: nkeynes@614: } else { nkeynes@736: char *id = g_strstrip(strv[0]); nkeynes@736: GList *ptr; nkeynes@736: for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) { nkeynes@736: input_driver_entry_t entry = (input_driver_entry_t)ptr->data; nkeynes@736: if( strcasecmp( entry->driver->id, id ) == 0 ) { nkeynes@736: /* we have ze device */ nkeynes@736: if( entry->driver->resolve_keysym == NULL ) { nkeynes@736: g_strfreev(strv); nkeynes@736: return NULL; nkeynes@736: } nkeynes@736: uint16_t keycode = entry->driver->resolve_keysym(entry->driver, g_strstrip(strv[1])); nkeynes@736: g_strfreev(strv); nkeynes@736: if( keycode == 0 || keycode > entry->entry_count ) { nkeynes@736: return NULL; nkeynes@736: } nkeynes@736: return &entry->keymap[keycode-1]; nkeynes@736: } nkeynes@736: } nkeynes@736: g_strfreev(strv); nkeynes@736: return NULL; // device not found nkeynes@614: } nkeynes@144: } nkeynes@144: nkeynes@614: static struct keymap_entry **input_entry_from_keycode( input_driver_t driver, uint16_t keycode ) nkeynes@614: { nkeynes@614: GList *ptr; nkeynes@614: nkeynes@614: if( keycode == 0 ) { nkeynes@736: return NULL; nkeynes@614: } nkeynes@614: nkeynes@614: if( driver == NULL ) { nkeynes@736: return &root_keymap[keycode-1]; nkeynes@614: } nkeynes@614: nkeynes@614: for( ptr = input_drivers; ptr != NULL; ptr = g_list_next(ptr) ) { nkeynes@736: input_driver_entry_t entry = (input_driver_entry_t)ptr->data; nkeynes@736: if( entry->driver == driver ) { nkeynes@736: if( keycode > entry->entry_count ) { nkeynes@736: return NULL; nkeynes@736: } else { nkeynes@736: return &entry->keymap[keycode-1]; nkeynes@736: } nkeynes@736: } nkeynes@614: } nkeynes@614: return NULL; nkeynes@614: } nkeynes@614: nkeynes@770: gchar *input_keycode_to_keysym( input_driver_t driver, uint16_t keycode ) nkeynes@614: { nkeynes@614: if( keycode == 0 ) { nkeynes@736: return NULL; nkeynes@614: } nkeynes@614: if( driver == NULL ) { nkeynes@736: if( display_driver != NULL && display_driver->get_keysym_for_keycode != NULL ) { nkeynes@736: return display_driver->get_keysym_for_keycode(keycode); nkeynes@736: } nkeynes@614: } else if( driver->get_keysym_for_keycode ) { nkeynes@736: gchar *sym = driver->get_keysym_for_keycode(driver,keycode); nkeynes@736: if( sym != NULL ) { nkeynes@736: gchar *result = g_strdup_printf( "%s: %s", driver->id, sym ); nkeynes@736: g_free(sym); nkeynes@736: return result; nkeynes@736: } nkeynes@614: } nkeynes@614: return NULL; nkeynes@614: } nkeynes@614: nkeynes@614: nkeynes@144: gboolean input_register_key( const gchar *keysym, input_key_callback_t callback, nkeynes@736: void *data, uint32_t value ) nkeynes@144: { nkeynes@614: if( keysym == NULL ) { nkeynes@736: return FALSE; nkeynes@614: } nkeynes@614: int keys = 0; nkeynes@271: gchar **strv = g_strsplit(keysym, ",", 16); nkeynes@271: gchar **s = strv; nkeynes@271: while( *s != NULL ) { nkeynes@736: keymap_entry_t *entryp = input_entry_from_keysym(*s); nkeynes@736: if( entryp != NULL ) { nkeynes@736: *entryp = g_malloc0(sizeof(struct keymap_entry)); nkeynes@736: (*entryp)->callback = callback; nkeynes@736: (*entryp)->data = data; nkeynes@736: (*entryp)->value = value; nkeynes@736: keys++; nkeynes@736: } nkeynes@736: s++; nkeynes@271: } nkeynes@271: g_strfreev(strv); nkeynes@614: return keys != 0; nkeynes@144: } nkeynes@144: nkeynes@451: void input_unregister_key( const gchar *keysym, input_key_callback_t callback, nkeynes@736: void *data, uint32_t value ) nkeynes@144: { nkeynes@614: if( keysym == NULL ) { nkeynes@736: return; nkeynes@614: } nkeynes@614: nkeynes@614: gchar **strv = g_strsplit(keysym, ",", 16); nkeynes@614: gchar **s = strv; nkeynes@614: while( *s != NULL ) { nkeynes@736: keymap_entry_t *entryp = input_entry_from_keysym(*s); nkeynes@736: if( entryp != NULL && *entryp != NULL && (*entryp)->callback == callback && nkeynes@736: (*entryp)->data == data && (*entryp)->value == value ) { nkeynes@736: g_free( *entryp ); nkeynes@736: *entryp = NULL; nkeynes@736: } nkeynes@736: s++; nkeynes@614: } nkeynes@614: g_strfreev(strv); nkeynes@144: } nkeynes@608: nkeynes@849: gboolean input_register_keyboard_hook( input_key_callback_t callback, nkeynes@736: void *data ) nkeynes@608: { nkeynes@608: keymap_entry_t key = malloc( sizeof( struct keymap_entry ) ); nkeynes@608: assert( key != NULL ); nkeynes@608: key->callback = callback; nkeynes@608: key->data = data; nkeynes@608: key->next = keyhooks; nkeynes@608: keyhooks = key; nkeynes@608: return TRUE; nkeynes@608: } nkeynes@608: nkeynes@849: void input_unregister_keyboard_hook( input_key_callback_t callback, nkeynes@736: void *data ) nkeynes@608: { nkeynes@608: keymap_entry_t key = keyhooks; nkeynes@608: if( key != NULL ) { nkeynes@736: if( key->callback == callback && key->data == data ) { nkeynes@736: keyhooks = keyhooks->next; nkeynes@736: free(key); nkeynes@736: return; nkeynes@736: } nkeynes@736: while( key->next != NULL ) { nkeynes@736: if( key->next->callback == callback && key->next->data == data ) { nkeynes@627: keymap_entry_t next = key->next; nkeynes@736: key->next = next->next; nkeynes@736: free(next); nkeynes@736: return; nkeynes@736: } nkeynes@736: key = key->next; nkeynes@736: } nkeynes@608: } nkeynes@608: } nkeynes@608: nkeynes@849: gboolean input_is_key_valid( const gchar *keysym ) nkeynes@849: { nkeynes@849: keymap_entry_t *ptr = input_entry_from_keysym(keysym); nkeynes@849: return ptr != NULL; nkeynes@849: } nkeynes@849: nkeynes@849: gboolean input_is_key_registered( const gchar *keysym ) nkeynes@849: { nkeynes@849: keymap_entry_t *ptr = input_entry_from_keysym(keysym); nkeynes@849: return ptr != NULL && *ptr != NULL; nkeynes@849: } nkeynes@849: nkeynes@849: void input_event_keydown( input_driver_t driver, uint16_t keycode, uint32_t pressure ) nkeynes@849: { nkeynes@849: if( display_focused ) { nkeynes@849: keymap_entry_t *entryp = input_entry_from_keycode(driver,keycode); nkeynes@849: if( entryp != NULL && *entryp != NULL ) { nkeynes@849: (*entryp)->callback( (*entryp)->data, (*entryp)->value, pressure, TRUE ); nkeynes@849: } nkeynes@849: if( driver == NULL ) { nkeynes@849: keymap_entry_t key = keyhooks; nkeynes@849: while( key != NULL ) { nkeynes@849: key->callback( key->data, keycode, pressure, TRUE ); nkeynes@849: key = key->next; nkeynes@849: } nkeynes@849: } nkeynes@849: } nkeynes@849: if( display_keysym_hook != NULL ) { nkeynes@849: gchar *sym = input_keycode_to_keysym( driver, keycode ); nkeynes@849: if( sym != NULL ) { nkeynes@849: display_keysym_hook(display_keysym_hook_data, sym); nkeynes@849: g_free(sym); nkeynes@849: } nkeynes@849: } nkeynes@849: } nkeynes@849: nkeynes@1010: void input_event_keyup( input_driver_t driver, uint16_t keycode ) nkeynes@849: { nkeynes@849: if( display_focused ) { nkeynes@849: keymap_entry_t *entryp = input_entry_from_keycode(driver,keycode); nkeynes@849: if( entryp != NULL && *entryp != NULL ) { nkeynes@1010: (*entryp)->callback( (*entryp)->data, (*entryp)->value, 0, FALSE ); nkeynes@849: } nkeynes@849: nkeynes@849: if( driver == NULL ) { nkeynes@849: keymap_entry_t key = keyhooks; nkeynes@849: while( key != NULL ) { nkeynes@1010: key->callback( key->data, keycode, 0, FALSE ); nkeynes@849: key = key->next; nkeynes@849: } nkeynes@849: } nkeynes@849: } nkeynes@849: } nkeynes@849: nkeynes@849: uint16_t input_keycode_to_dckeysym( uint16_t keycode ) nkeynes@849: { nkeynes@849: return display_driver->convert_to_dckeysym(keycode); nkeynes@849: } nkeynes@849: nkeynes@849: void input_set_keysym_hook( display_keysym_callback_t hook, void *data ) nkeynes@849: { nkeynes@849: display_keysym_hook = hook; nkeynes@849: display_keysym_hook_data = data; nkeynes@849: } nkeynes@849: nkeynes@849: /***************** System mouse driver ****************/ nkeynes@849: nkeynes@849: static struct keymap_entry *mouse_keymap[MAX_MOUSE_BUTTONS]; nkeynes@849: static struct mouse_entry *mousehooks = NULL; nkeynes@849: static uint32_t mouse_x = -1, mouse_y = -1, mouse_buttons = 0; nkeynes@849: nkeynes@849: uint16_t mouse_resolve_keysym( struct input_driver *driver, const gchar *keysym ) nkeynes@849: { nkeynes@849: if( strncasecmp( keysym, "Button", 6 ) == 0 ){ nkeynes@849: unsigned long button = strtoul( keysym+6, NULL, 10 ); nkeynes@849: if( button > MAX_MOUSE_BUTTONS ) { nkeynes@849: return 0; nkeynes@849: } nkeynes@849: return (uint16_t)button; nkeynes@849: } nkeynes@849: return 0; nkeynes@849: } nkeynes@849: nkeynes@849: gchar *mouse_get_keysym( struct input_driver *driver, uint16_t keycode ) nkeynes@849: { nkeynes@849: return g_strdup_printf( "Button%d", (keycode) ); nkeynes@849: } nkeynes@849: nkeynes@849: struct input_driver system_mouse_driver = { "Mouse", mouse_resolve_keysym, NULL, mouse_get_keysym, NULL }; nkeynes@849: nkeynes@849: nkeynes@608: gboolean input_register_mouse_hook( gboolean relative, input_mouse_callback_t callback, nkeynes@736: void *data ) nkeynes@608: { nkeynes@608: mouse_entry_t ent = malloc( sizeof( struct mouse_entry ) ); nkeynes@608: assert( ent != NULL ); nkeynes@608: ent->callback = callback; nkeynes@608: ent->data = data; nkeynes@608: ent->next = mousehooks; nkeynes@608: mousehooks = ent; nkeynes@608: return TRUE; nkeynes@608: } nkeynes@608: nkeynes@608: void input_unregister_mouse_hook( input_mouse_callback_t callback, void *data ) nkeynes@608: { nkeynes@608: mouse_entry_t ent = mousehooks; nkeynes@608: if( ent != NULL ) { nkeynes@736: if( ent->callback == callback && ent->data == data ) { nkeynes@736: mousehooks = mousehooks->next; nkeynes@736: free(ent); nkeynes@736: return; nkeynes@736: } nkeynes@736: while( ent->next != NULL ) { nkeynes@736: if( ent->next->callback == callback && ent->next->data == data ) { nkeynes@627: mouse_entry_t next = ent->next; nkeynes@736: ent->next = next->next; nkeynes@736: free(next); nkeynes@736: return; nkeynes@736: } nkeynes@736: ent = ent->next; nkeynes@736: } nkeynes@608: } nkeynes@608: } nkeynes@608: nkeynes@849: void input_event_run_mouse_hooks( uint32_t buttons, int32_t x, int32_t y, gboolean absolute ) nkeynes@608: { nkeynes@608: mouse_entry_t ent = mousehooks; nkeynes@608: while( ent != NULL ) { nkeynes@839: ent->callback(ent->data, buttons, x, y, absolute); nkeynes@736: ent = ent->next; nkeynes@608: } nkeynes@608: } nkeynes@144: nkeynes@849: void input_event_mousedown( uint16_t button, int32_t x, int32_t y, gboolean absolute ) nkeynes@144: { nkeynes@849: if( absolute ) { nkeynes@849: mouse_x = x; nkeynes@849: mouse_y = y; nkeynes@849: } nkeynes@849: mouse_buttons |= (1<name, nkeynes@736: gettext(display_driver_list[i]->description) ); nkeynes@700: } nkeynes@700: } nkeynes@700: nkeynes@531: display_driver_t get_display_driver_by_name( const char *name ) nkeynes@531: { nkeynes@531: int i; nkeynes@531: if( name == NULL ) { nkeynes@736: return display_driver_list[0]; nkeynes@531: } nkeynes@531: for( i=0; display_driver_list[i] != NULL; i++ ) { nkeynes@736: if( strcasecmp( display_driver_list[i]->name, name ) == 0 ) { nkeynes@736: return display_driver_list[i]; nkeynes@736: } nkeynes@531: } nkeynes@531: nkeynes@531: return NULL; nkeynes@531: } nkeynes@144: nkeynes@144: nkeynes@370: gboolean display_set_driver( display_driver_t driver ) nkeynes@144: { nkeynes@370: gboolean rv = TRUE; nkeynes@370: if( display_driver != NULL && display_driver->shutdown_driver != NULL ) nkeynes@736: display_driver->shutdown_driver(); nkeynes@144: nkeynes@144: display_driver = driver; nkeynes@144: if( driver->init_driver != NULL ) nkeynes@736: rv = driver->init_driver(); nkeynes@849: if( rv ) { nkeynes@849: input_register_device(&system_mouse_driver, MAX_MOUSE_BUTTONS); nkeynes@849: } else { nkeynes@736: display_driver = NULL; nkeynes@370: } nkeynes@370: return rv; nkeynes@144: } nkeynes@614: nkeynes@614: void display_set_focused( gboolean has_focus ) nkeynes@614: { nkeynes@614: display_focused = has_focus; nkeynes@614: }