/* (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) (c) Copyright 2000-2004 Convergence (integrated media) GmbH All rights reserved. Written by Denis Oliver Kropp , Andreas Hundt , Sven Neumann , Ville Syrjälä and Claudio Ciccani . This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include D_DEBUG_DOMAIN( Core_Input, "Core/Input", "DirectFB Input Core" ); D_DEBUG_DOMAIN( Core_InputEvt, "Core/Input/Evt", "DirectFB Input Core Events & Dispatch" ); DEFINE_MODULE_DIRECTORY( dfb_input_modules, "inputdrivers", DFB_INPUT_DRIVER_ABI_VERSION ); /**********************************************************************************************************************/ typedef enum { CICC_RESCAN_DEVICES } CoreInputCoreCommand; typedef enum { CIDC_RELOAD_KEYMAP, CIDC_SET_SENSITIVITY } CoreInputDeviceCommand; typedef struct { DirectLink link; int magic; DirectModuleEntry *module; const InputDriverFuncs *funcs; InputDriverInfo info; int nr_devices; } InputDriver; typedef struct { int min_keycode; int max_keycode; int num_entries; DFBInputDeviceKeymapEntry *entries; } InputDeviceKeymap; typedef struct { int magic; DFBInputDeviceID id; /* unique device id */ int num; InputDeviceInfo device_info; InputDeviceKeymap keymap; DFBInputDeviceModifierMask modifiers_l; DFBInputDeviceModifierMask modifiers_r; DFBInputDeviceLockState locks; DFBInputDeviceButtonMask buttons; DFBInputDeviceKeyIdentifier last_key; /* last key pressed */ DFBInputDeviceKeySymbol last_symbol; /* last symbol pressed */ bool first_press; /* first press of key */ FusionReactor *reactor; /* event dispatcher */ FusionSkirmish lock; FusionCall call; /* driver call via master */ unsigned int axis_num; DFBInputDeviceAxisInfo *axis_info; DFBInputDeviceState state; } InputDeviceShared; struct __DFB_CoreInputDevice { int magic; InputDeviceShared *shared; InputDriver *driver; void *driver_data; CoreDFB *core; }; /**********************************************************************************************************************/ typedef struct { int magic; int num; InputDeviceShared *devices[MAX_INPUTDEVICES]; FusionCall call; FusionReactor *reactor; } DFBInputCoreShared; struct __DFB_DFBInputCore { int magic; CoreDFB *core; DFBInputCoreShared *shared; DirectLink *drivers; int num; CoreInputDevice *devices[MAX_INPUTDEVICES]; Reaction reaction; }; DFB_CORE_PART( input_core, InputCore ); /**********************************************************************************************************************/ typedef struct { DFBInputDeviceKeySymbol target; DFBInputDeviceKeySymbol result; } DeadKeyCombo; typedef struct { DFBInputDeviceKeySymbol deadkey; const DeadKeyCombo *combos; } DeadKeyMap; /**********************************************************************************************************************/ static const DeadKeyCombo combos_grave[] = { { DIKS_SPACE, (unsigned char) '`' }, { DIKS_SMALL_A, (unsigned char) 'à' }, { DIKS_SMALL_E, (unsigned char) 'è' }, { DIKS_SMALL_I, (unsigned char) 'ì' }, { DIKS_SMALL_O, (unsigned char) 'ò' }, { DIKS_SMALL_U, (unsigned char) 'ù' }, { DIKS_CAPITAL_A, (unsigned char) 'À' }, { DIKS_CAPITAL_E, (unsigned char) 'È' }, { DIKS_CAPITAL_I, (unsigned char) 'Ì' }, { DIKS_CAPITAL_O, (unsigned char) 'Ò' }, { DIKS_CAPITAL_U, (unsigned char) 'Ù' }, { 0, 0 } }; static const DeadKeyCombo combos_acute[] = { { DIKS_SPACE, (unsigned char) '\'' }, { DIKS_SMALL_A, (unsigned char) 'á' }, { DIKS_SMALL_E, (unsigned char) 'é' }, { DIKS_SMALL_I, (unsigned char) 'í' }, { DIKS_SMALL_O, (unsigned char) 'ó' }, { DIKS_SMALL_U, (unsigned char) 'ú' }, { DIKS_SMALL_Y, (unsigned char) 'ý' }, { DIKS_CAPITAL_A, (unsigned char) 'Á' }, { DIKS_CAPITAL_E, (unsigned char) 'É' }, { DIKS_CAPITAL_I, (unsigned char) 'Í' }, { DIKS_CAPITAL_O, (unsigned char) 'Ó' }, { DIKS_CAPITAL_U, (unsigned char) 'Ú' }, { DIKS_CAPITAL_Y, (unsigned char) 'Ý' }, { 0, 0 } }; static const DeadKeyCombo combos_circumflex[] = { { DIKS_SPACE, (unsigned char) '^' }, { DIKS_SMALL_A, (unsigned char) 'â' }, { DIKS_SMALL_E, (unsigned char) 'ê' }, { DIKS_SMALL_I, (unsigned char) 'î' }, { DIKS_SMALL_O, (unsigned char) 'ô' }, { DIKS_SMALL_U, (unsigned char) 'û' }, { DIKS_CAPITAL_A, (unsigned char) 'Â' }, { DIKS_CAPITAL_E, (unsigned char) 'Ê' }, { DIKS_CAPITAL_I, (unsigned char) 'Î' }, { DIKS_CAPITAL_O, (unsigned char) 'Ô' }, { DIKS_CAPITAL_U, (unsigned char) 'Û' }, { 0, 0 } }; static const DeadKeyCombo combos_diaeresis[] = { { DIKS_SPACE, (unsigned char) '¨' }, { DIKS_SMALL_A, (unsigned char) 'ä' }, { DIKS_SMALL_E, (unsigned char) 'ë' }, { DIKS_SMALL_I, (unsigned char) 'ï' }, { DIKS_SMALL_O, (unsigned char) 'ö' }, { DIKS_SMALL_U, (unsigned char) 'ü' }, { DIKS_CAPITAL_A, (unsigned char) 'Ä' }, { DIKS_CAPITAL_E, (unsigned char) 'Ë' }, { DIKS_CAPITAL_I, (unsigned char) 'Ï' }, { DIKS_CAPITAL_O, (unsigned char) 'Ö' }, { DIKS_CAPITAL_U, (unsigned char) 'Ü' }, { 0, 0 } }; static const DeadKeyCombo combos_tilde[] = { { DIKS_SPACE, (unsigned char) '~' }, { DIKS_SMALL_A, (unsigned char) 'ã' }, { DIKS_SMALL_N, (unsigned char) 'ñ' }, { DIKS_SMALL_O, (unsigned char) 'õ' }, { DIKS_CAPITAL_A, (unsigned char) 'Ã' }, { DIKS_CAPITAL_N, (unsigned char) 'Ñ' }, { DIKS_CAPITAL_O, (unsigned char) 'Õ' }, { 0, 0 } }; static const DeadKeyMap deadkey_maps[] = { { DIKS_DEAD_GRAVE, combos_grave }, { DIKS_DEAD_ACUTE, combos_acute }, { DIKS_DEAD_CIRCUMFLEX, combos_circumflex }, { DIKS_DEAD_DIAERESIS, combos_diaeresis }, { DIKS_DEAD_TILDE, combos_tilde } }; /* define a lookup table to go from key IDs to names. * This is used to look up the names provided in a loaded key table */ /* this table is roughly 4Kb in size */ DirectFBKeySymbolNames(KeySymbolNames); DirectFBKeyIdentifierNames(KeyIdentifierNames); /**********************************************************************************************************************/ static void init_drivers ( CoreDFB *core ); static DFBResult rescan_devices( CoreDFB *core ); static void allocate_device_keymap( CoreDFB *core, CoreInputDevice *device ); static DFBInputDeviceKeymapEntry *get_keymap_entry( CoreInputDevice *device, int code ); static DFBResult set_keymap_entry( CoreInputDevice *device, int code, DFBInputDeviceKeymapEntry *entry ); static DFBResult load_keymap( CoreInputDevice *device, char *filename ); static DFBInputDeviceKeySymbol lookup_keysymbol( char *symbolname ); static DFBInputDeviceKeyIdentifier lookup_keyidentifier( char *identifiername ); /**********************************************************************************************************************/ static bool lookup_from_table( CoreInputDevice *device, DFBInputEvent *event, DFBInputEventFlags lookup ); static void fixup_key_event ( CoreInputDevice *device, DFBInputEvent *event ); static void fixup_mouse_event( CoreInputDevice *device, DFBInputEvent *event ); static void flush_keys ( CoreInputDevice *device ); static bool core_input_filter( CoreInputDevice *device, DFBInputEvent *event ); /**********************************************************************************************************************/ static DFBInputDeviceKeyIdentifier symbol_to_id( DFBInputDeviceKeySymbol symbol ); static DFBInputDeviceKeySymbol id_to_symbol( DFBInputDeviceKeyIdentifier id, DFBInputDeviceModifierMask modifiers, DFBInputDeviceLockState locks ); /**********************************************************************************************************************/ static ReactionFunc dfb_input_globals[MAX_INPUT_GLOBALS+1] = { /* 0 */ _dfb_windowstack_inputdevice_listener, NULL }; DFBResult dfb_input_add_global( ReactionFunc func, int *ret_index ) { int i; D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, func, ret_index ); D_ASSERT( func != NULL ); D_ASSERT( ret_index != NULL ); for (i=0; i index %d\n", i ); *ret_index = i; return DFB_OK; } } return DFB_LIMITEXCEEDED; } DFBResult dfb_input_set_global( ReactionFunc func, int index ) { D_DEBUG_AT( Core_Input, "%s( %p, %d )\n", __FUNCTION__, func, index ); D_ASSERT( func != NULL ); D_ASSERT( index >= 0 ); D_ASSERT( index < MAX_INPUT_GLOBALS ); D_ASSUME( dfb_input_globals[index] == NULL ); dfb_input_globals[index] = func; return DFB_OK; } /**********************************************************************************************************************/ static DFBInputCore *core_local; /* FIXME */ static DFBInputCoreShared *core_input; /* FIXME */ /**********************************************************************************************************************/ static FusionCallHandlerResult core_input_call_handler( int caller, /* fusion id of the caller */ int call_arg, /* optional call parameter */ void *call_ptr, /* optional call parameter */ void *ctx, /* optional handler context */ unsigned int serial, int *ret_val ) { CoreDFB *core = ctx; D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, core ); switch (call_arg) { case CICC_RESCAN_DEVICES: *ret_val = rescan_devices( core ); break; default: D_BUG( "unknown command %d", call_arg ); *ret_val = DFB_BUG; } return FCHR_RETURN; } /**********************************************************************************************************************/ static DFBResult dfb_input_core_initialize( CoreDFB *core, DFBInputCore *data, DFBInputCoreShared *shared ) { D_DEBUG_AT( Core_Input, "dfb_input_core_initialize( %p, %p, %p )\n", core, data, shared ); D_ASSERT( data != NULL ); D_ASSERT( shared != NULL ); core_local = data; /* FIXME */ core_input = shared; /* FIXME */ data->core = core; data->shared = shared; fusion_call_init( &core_input->call, core_input_call_handler, core, dfb_core_world( core ) ); core_input->reactor = fusion_reactor_new( sizeof(CoreInputCoreNotification), "Input Core", dfb_core_world( core ) ); fusion_reactor_direct( core_input->reactor, false ); direct_modules_explore_directory( &dfb_input_modules ); init_drivers( core ); rescan_devices( core ); D_MAGIC_SET( data, DFBInputCore ); D_MAGIC_SET( shared, DFBInputCoreShared ); return DFB_OK; } static DFBResult rejoin_devices( CoreDFB *core ) { int i; D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, core ); D_ASSERT( core != NULL ); D_MAGIC_ASSERT( core_local, DFBInputCore ); D_ASSERT( core_input != NULL ); for (i=core_local->num; inum; i++) { CoreInputDevice *device; D_DEBUG_AT( Core_Input, " -> adding %d (%s)\n", core_input->devices[i]->id, core_input->devices[i]->device_info.desc.name ); device = D_CALLOC( 1, sizeof(CoreInputDevice) ); if (!device) { D_OOM(); continue; } device->shared = core_input->devices[i]; D_MAGIC_SET( device, CoreInputDevice ); /* add it to the list */ core_local->devices[core_local->num++] = device; } return DFB_OK; } static ReactionResult core_input_core_reaction( const void *msg_data, void *ctx ) { const CoreInputCoreNotification *notification = msg_data; CoreDFB *core = ctx; if (notification->flags & CICNF_NEW_DEVICE) rejoin_devices( core ); return RS_OK; } static DFBResult dfb_input_core_join( CoreDFB *core, DFBInputCore *data, DFBInputCoreShared *shared ) { D_DEBUG_AT( Core_Input, "dfb_input_core_join( %p, %p, %p )\n", core, data, shared ); D_ASSERT( data != NULL ); D_MAGIC_ASSERT( shared, DFBInputCoreShared ); core_local = data; /* FIXME */ core_input = shared; /* FIXME */ data->core = core; data->shared = shared; D_MAGIC_SET( data, DFBInputCore ); rejoin_devices( core ); fusion_reactor_attach( core_input->reactor, core_input_core_reaction, core, &core_local->reaction ); return DFB_OK; } static DFBResult dfb_input_core_shutdown( DFBInputCore *data, bool emergency ) { int i; DFBInputCoreShared *shared; FusionSHMPoolShared *pool = dfb_core_shmpool( data->core ); D_DEBUG_AT( Core_Input, "dfb_input_core_shutdown( %p, %semergency )\n", data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBInputCore ); D_MAGIC_ASSERT( data->shared, DFBInputCoreShared ); shared = data->shared; for (i=0; inum; i++) { CoreInputDevice *device = data->devices[i]; InputDriver *driver; InputDeviceShared *devshared; D_MAGIC_ASSERT( device, CoreInputDevice ); driver = device->driver; D_ASSERT( driver != NULL ); devshared = device->shared; D_ASSERT( devshared != NULL ); fusion_call_destroy( &devshared->call ); fusion_skirmish_destroy( &devshared->lock ); if (device->driver_data != NULL) { void *driver_data; D_ASSERT( driver->funcs != NULL ); D_ASSERT( driver->funcs->CloseDevice != NULL ); D_DEBUG_AT( Core_Input, " -> closing '%s' (%d) %d.%d (%s)\n", devshared->device_info.desc.name, devshared->num + 1, driver->info.version.major, driver->info.version.minor, driver->info.vendor ); driver_data = device->driver_data; device->driver_data = NULL; driver->funcs->CloseDevice( driver_data ); } if (!--driver->nr_devices) { direct_module_unref( driver->module ); D_FREE( driver ); } fusion_reactor_free( devshared->reactor ); if (devshared->keymap.entries) SHFREE( pool, devshared->keymap.entries ); if (devshared->axis_info) SHFREE( pool, devshared->axis_info ); SHFREE( pool, devshared ); D_MAGIC_CLEAR( device ); D_FREE( device ); } D_MAGIC_CLEAR( data ); D_MAGIC_CLEAR( shared ); return DFB_OK; } static DFBResult dfb_input_core_leave( DFBInputCore *data, bool emergency ) { int i; DFBInputCoreShared *shared; D_DEBUG_AT( Core_Input, "dfb_input_core_leave( %p, %semergency )\n", data, emergency ? "" : "no " ); D_MAGIC_ASSERT( data, DFBInputCore ); D_MAGIC_ASSERT( data->shared, DFBInputCoreShared ); shared = data->shared; for (i=0; inum; i++) { CoreInputDevice *device = data->devices[i]; D_MAGIC_ASSERT( device, CoreInputDevice ); D_FREE( device ); } D_MAGIC_CLEAR( data ); return DFB_OK; } static DFBResult dfb_input_core_suspend( DFBInputCore *data ) { int i; DFBInputCoreShared *shared; D_DEBUG_AT( Core_Input, "dfb_input_core_suspend( %p )\n", data ); D_MAGIC_ASSERT( data, DFBInputCore ); D_MAGIC_ASSERT( data->shared, DFBInputCoreShared ); shared = data->shared; D_DEBUG_AT( Core_Input, " -> suspending...\n" ); for (i=0; inum; i++) { CoreInputDevice *device = data->devices[i]; InputDriver *driver; InputDeviceShared *devshared; D_MAGIC_ASSERT( device, CoreInputDevice ); driver = device->driver; D_ASSERT( driver != NULL ); devshared = device->shared; D_ASSERT( devshared != NULL ); if (device->driver_data != NULL) { void *driver_data; D_ASSERT( driver->funcs != NULL ); D_ASSERT( driver->funcs->CloseDevice != NULL ); D_DEBUG_AT( Core_Input, " -> closing '%s' (%d) %d.%d (%s)\n", devshared->device_info.desc.name, devshared->num + 1, driver->info.version.major, driver->info.version.minor, driver->info.vendor ); driver_data = device->driver_data; device->driver_data = NULL; driver->funcs->CloseDevice( driver_data ); } flush_keys( device ); } D_DEBUG_AT( Core_Input, " -> suspended.\n" ); return DFB_OK; } static DFBResult dfb_input_core_resume( DFBInputCore *data ) { DFBInputCoreShared *shared; DFBResult ret; int i; D_DEBUG_AT( Core_Input, "dfb_input_core_resume( %p )\n", data ); D_MAGIC_ASSERT( data, DFBInputCore ); D_MAGIC_ASSERT( data->shared, DFBInputCoreShared ); shared = data->shared; D_DEBUG_AT( Core_Input, " -> resuming...\n" ); for (i=0; inum; i++) { CoreInputDevice *device = data->devices[i]; D_MAGIC_ASSERT( device, CoreInputDevice ); D_DEBUG_AT( Core_Input, " -> reopening '%s' (%d) %d.%d (%s)\n", device->shared->device_info.desc.name, device->shared->num + 1, device->driver->info.version.major, device->driver->info.version.minor, device->driver->info.vendor ); D_ASSERT( device->driver_data == NULL ); ret = device->driver->funcs->OpenDevice( device, device->shared->num, &device->shared->device_info, &device->driver_data ); if (ret) { D_DERROR( ret, "DirectFB/Input: Failed reopening device " "during resume (%s)!\n", device->shared->device_info.desc.name ); device->driver_data = NULL; } } D_DEBUG_AT( Core_Input, " -> resumed.\n" ); return DFB_OK; } void dfb_input_enumerate_devices( InputDeviceCallback callback, void *ctx, DFBInputDeviceCapabilities caps ) { int i; D_ASSERT( core_input != NULL ); for (i=0; inum; i++) { CoreInputDevice *device = core_local->devices[i]; DFBInputDeviceCapabilities dev_caps; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( device->shared != NULL ); dev_caps = device->shared->device_info.desc.caps; /* Always match if unclassified */ if (!dev_caps) dev_caps = DICAPS_ALL; if ((dev_caps & caps) && callback( device, ctx ) == DFENUM_CANCEL) break; } } DirectResult dfb_input_attach( CoreInputDevice *device, ReactionFunc func, void *ctx, Reaction *reaction ) { D_DEBUG_AT( Core_Input, "%s( %p, %p, %p, %p )\n", __FUNCTION__, device, func, ctx, reaction ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device != NULL ); D_ASSERT( device->shared != NULL ); return fusion_reactor_attach( device->shared->reactor, func, ctx, reaction ); } DirectResult dfb_input_detach( CoreInputDevice *device, Reaction *reaction ) { D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, device, reaction ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device != NULL ); D_ASSERT( device->shared != NULL ); return fusion_reactor_detach( device->shared->reactor, reaction ); } DirectResult dfb_input_attach_global( CoreInputDevice *device, int index, void *ctx, GlobalReaction *reaction ) { D_DEBUG_AT( Core_Input, "%s( %p, %d, %p, %p )\n", __FUNCTION__, device, index, ctx, reaction ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device != NULL ); D_ASSERT( device->shared != NULL ); return fusion_reactor_attach_global( device->shared->reactor, index, ctx, reaction ); } DirectResult dfb_input_detach_global( CoreInputDevice *device, GlobalReaction *reaction ) { D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, device, reaction ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device != NULL ); D_ASSERT( device->shared != NULL ); return fusion_reactor_detach_global( device->shared->reactor, reaction ); } const char * dfb_input_event_type_name( DFBInputEventType type ) { switch (type) { case DIET_UNKNOWN: return "UNKNOWN"; case DIET_KEYPRESS: return "KEYPRESS"; case DIET_KEYRELEASE: return "KEYRELEASE"; case DIET_BUTTONPRESS: return "BUTTONPRESS"; case DIET_BUTTONRELEASE: return "BUTTONRELEASE"; case DIET_AXISMOTION: return "AXISMOTION"; default: break; } return ""; } void dfb_input_dispatch( CoreInputDevice *device, DFBInputEvent *event ) { D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, device, event ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device != NULL ); D_ASSERT( event != NULL ); D_ASSUME( device->shared != NULL ); /* * 0. Sanity checks & debugging... */ if (!device->shared) { D_DEBUG_AT( Core_Input, " -> No shared data!\n" ); return; } D_ASSUME( device->shared->reactor != NULL ); if (!device->shared->reactor) { D_DEBUG_AT( Core_Input, " -> No reactor!\n" ); return; } D_DEBUG_AT( Core_InputEvt, " -> (%02x) %s%s%s\n", event->type, dfb_input_event_type_name( event->type ), (event->flags & DIEF_FOLLOW) ? " [FOLLOW]" : "", (event->flags & DIEF_REPEAT) ? " [REPEAT]" : "" ); #if D_DEBUG_ENABLED if (event->flags & DIEF_TIMESTAMP) D_DEBUG_AT( Core_InputEvt, " -> TIMESTAMP %lu.%06lu\n", event->timestamp.tv_sec, event->timestamp.tv_usec ); if (event->flags & DIEF_AXISABS) D_DEBUG_AT( Core_InputEvt, " -> AXISABS %d at %d\n", event->axis, event->axisabs ); if (event->flags & DIEF_AXISREL) D_DEBUG_AT( Core_InputEvt, " -> AXISREL %d by %d\n", event->axis, event->axisrel ); if (event->flags & DIEF_KEYCODE) D_DEBUG_AT( Core_InputEvt, " -> KEYCODE %d\n", event->key_code ); if (event->flags & DIEF_KEYID) D_DEBUG_AT( Core_InputEvt, " -> KEYID 0x%04x\n", event->key_id ); if (event->flags & DIEF_KEYSYMBOL) D_DEBUG_AT( Core_InputEvt, " -> KEYSYMBOL 0x%04x\n", event->key_symbol ); if (event->flags & DIEF_MODIFIERS) D_DEBUG_AT( Core_InputEvt, " -> MODIFIERS 0x%04x\n", event->modifiers ); if (event->flags & DIEF_LOCKS) D_DEBUG_AT( Core_InputEvt, " -> LOCKS 0x%04x\n", event->locks ); if (event->flags & DIEF_BUTTONS) D_DEBUG_AT( Core_InputEvt, " -> BUTTONS 0x%04x\n", event->buttons ); if (event->flags & DIEF_GLOBAL) D_DEBUG_AT( Core_InputEvt, " -> GLOBAL\n" ); #endif /* * 1. Fixup event... */ event->clazz = DFEC_INPUT; event->device_id = device->shared->id; if (!(event->flags & DIEF_TIMESTAMP)) { gettimeofday( &event->timestamp, NULL ); event->flags |= DIEF_TIMESTAMP; } switch (event->type) { case DIET_BUTTONPRESS: case DIET_BUTTONRELEASE: D_DEBUG_AT( Core_InputEvt, " -> BUTTON 0x%04x\n", event->button ); if (dfb_config->lefty) { if (event->button == DIBI_LEFT) event->button = DIBI_RIGHT; else if (event->button == DIBI_RIGHT) event->button = DIBI_LEFT; D_DEBUG_AT( Core_InputEvt, " -> lefty! => 0x%04x <=\n", event->button ); } /* fallthru */ case DIET_AXISMOTION: fixup_mouse_event( device, event ); break; case DIET_KEYPRESS: case DIET_KEYRELEASE: if (dfb_config->capslock_meta) { if (device->shared->keymap.num_entries && (event->flags & DIEF_KEYCODE)) lookup_from_table( device, event, (DIEF_KEYID | DIEF_KEYSYMBOL) & ~event->flags ); if (event->key_id == DIKI_CAPS_LOCK || event->key_symbol == DIKS_CAPS_LOCK) { event->flags |= DIEF_KEYID | DIEF_KEYSYMBOL; event->key_code = -1; event->key_id = DIKI_META_L; event->key_symbol = DIKS_META; } } fixup_key_event( device, event ); break; default: ; } #if D_DEBUG_ENABLED if (event->flags & DIEF_TIMESTAMP) D_DEBUG_AT( Core_InputEvt, " => TIMESTAMP %lu.%06lu\n", event->timestamp.tv_sec, event->timestamp.tv_usec ); if (event->flags & DIEF_AXISABS) D_DEBUG_AT( Core_InputEvt, " => AXISABS %d at %d\n", event->axis, event->axisabs ); if (event->flags & DIEF_AXISREL) D_DEBUG_AT( Core_InputEvt, " => AXISREL %d by %d\n", event->axis, event->axisrel ); if (event->flags & DIEF_KEYCODE) D_DEBUG_AT( Core_InputEvt, " => KEYCODE %d\n", event->key_code ); if (event->flags & DIEF_KEYID) D_DEBUG_AT( Core_InputEvt, " => KEYID 0x%04x\n", event->key_id ); if (event->flags & DIEF_KEYSYMBOL) D_DEBUG_AT( Core_InputEvt, " => KEYSYMBOL 0x%04x\n", event->key_symbol ); if (event->flags & DIEF_MODIFIERS) D_DEBUG_AT( Core_InputEvt, " => MODIFIERS 0x%04x\n", event->modifiers ); if (event->flags & DIEF_LOCKS) D_DEBUG_AT( Core_InputEvt, " => LOCKS 0x%04x\n", event->locks ); if (event->flags & DIEF_BUTTONS) D_DEBUG_AT( Core_InputEvt, " => BUTTONS 0x%04x\n", event->buttons ); if (event->flags & DIEF_GLOBAL) D_DEBUG_AT( Core_InputEvt, " => GLOBAL\n" ); #endif if (core_input_filter( device, event )) D_DEBUG_AT( Core_InputEvt, " ****>> FILTERED\n" ); else fusion_reactor_dispatch( device->shared->reactor, event, true, dfb_input_globals ); } DFBInputDeviceID dfb_input_device_id( const CoreInputDevice *device ) { D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device != NULL ); D_ASSERT( device->shared != NULL ); return device->shared->id; } CoreInputDevice * dfb_input_device_at( DFBInputDeviceID id ) { int i; D_ASSERT( core_input != NULL ); for (i=0; inum; i++) { CoreInputDevice *device = core_local->devices[i]; D_MAGIC_ASSERT( device, CoreInputDevice ); if (device->shared->id == id) return device; } return NULL; } void dfb_input_device_description( const CoreInputDevice *device, DFBInputDeviceDescription *desc ) { D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device != NULL ); D_ASSERT( device->shared != NULL ); *desc = device->shared->device_info.desc; } DFBResult dfb_input_device_get_keymap_entry( CoreInputDevice *device, int keycode, DFBInputDeviceKeymapEntry *entry ) { DFBInputDeviceKeymapEntry *keymap_entry; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device != NULL ); D_ASSERT( entry != NULL ); keymap_entry = get_keymap_entry( device, keycode ); if (!keymap_entry) return DFB_FAILURE; *entry = *keymap_entry; return DFB_OK; } DFBResult dfb_input_device_set_keymap_entry( CoreInputDevice *device, int keycode, DFBInputDeviceKeymapEntry *entry ) { D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device != NULL ); D_ASSERT( entry != NULL ); return set_keymap_entry( device, keycode, entry ); } DFBResult dfb_input_device_load_keymap ( CoreInputDevice *device, char *filename ) { D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device != NULL ); D_ASSERT( filename != NULL ); return load_keymap( device, filename ); } DFBResult dfb_input_device_reload_keymap( CoreInputDevice *device ) { int ret; InputDeviceShared *shared; D_MAGIC_ASSERT( device, CoreInputDevice ); shared = device->shared; D_ASSERT( shared != NULL ); D_INFO( "DirectFB/Input: Reloading keymap for '%s' [0x%02x]...\n", shared->device_info.desc.name, shared->id ); if (fusion_call_execute( &shared->call, FCEF_NONE, CIDC_RELOAD_KEYMAP, NULL, &ret )) return DFB_FUSION; return ret; } DFBResult dfb_input_device_set_sensitivity( CoreInputDevice *device, int sensitivity ) { int ret; InputDeviceShared *shared; D_MAGIC_ASSERT( device, CoreInputDevice ); shared = device->shared; D_ASSERT( shared != NULL ); if (fusion_call_execute( &shared->call, FCEF_NONE, CIDC_SET_SENSITIVITY, (void*)(long)sensitivity, &ret )) return DFB_FUSION; return ret; } DFBResult dfb_input_rescan_devices( CoreDFB *core ) { int ret; D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, core ); D_ASSERT( core_input != NULL ); if (fusion_call_execute( &core_input->call, FCEF_NODIRECT, CICC_RESCAN_DEVICES, NULL, &ret )) return DFB_FUSION; return ret; } DFBResult dfb_input_device_disconnected( CoreInputDevice *device ) { D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( device->shared != NULL ); D_ASSUME( !(device->shared->state.flags & DISTATE_DISCONNECTED) ); device->shared->state.flags |= DISTATE_DISCONNECTED; return DFB_OK; } DFBResult dfb_input_device_reconnected( CoreInputDevice *device ) { D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( device->shared != NULL ); D_ASSUME( device->shared->state.flags & DISTATE_DISCONNECTED ); device->shared->state.flags &= ~DISTATE_DISCONNECTED; return DFB_OK; } DFBResult dfb_input_device_get_state( const CoreInputDevice *device, DFBInputDeviceState *ret_state ) { D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( device->shared != NULL ); *ret_state = device->shared->state; return DFB_OK; } DFBResult dfb_input_core_attach( CoreDFB *core, ReactionFunc func, void *ctx, Reaction *reaction ) { D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, core ); D_ASSERT( core_input != NULL ); return fusion_reactor_attach( core_input->reactor, func, ctx, reaction ); } DFBResult dfb_input_core_detach( CoreDFB *core, Reaction *reaction ) { D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, core ); D_ASSERT( core_input != NULL ); return fusion_reactor_detach( core_input->reactor, reaction ); } /** internal **/ static void input_add_device( CoreInputDevice *device ) { CoreInputCoreNotification notification; D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device != NULL ); D_ASSERT( device->shared != NULL ); if (core_input->num == MAX_INPUTDEVICES) { D_ERROR( "DirectFB/Input: Maximum number of devices reached!\n" ); return; } core_local->devices[ core_local->num++ ] = device; core_input->devices[ core_input->num++ ] = device->shared; notification.flags = CICNF_NEW_DEVICE; notification.device_id = device->shared->id; fusion_reactor_dispatch( core_input->reactor, ¬ification, true, NULL ); } static void allocate_device_keymap( CoreDFB *core, CoreInputDevice *device ) { int i; DFBInputDeviceKeymapEntry *entries; FusionSHMPoolShared *pool = dfb_core_shmpool( core ); InputDeviceShared *shared = device->shared; DFBInputDeviceDescription *desc = &shared->device_info.desc; int num_entries = desc->max_keycode - desc->min_keycode + 1; D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, core, device ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); entries = SHCALLOC( pool, num_entries, sizeof(DFBInputDeviceKeymapEntry) ); if (!entries) { D_OOSHM(); return; } /* write -1 indicating entry is not fetched yet from driver */ for (i=0; ikeymap.min_keycode = desc->min_keycode; shared->keymap.max_keycode = desc->max_keycode; shared->keymap.num_entries = num_entries; shared->keymap.entries = entries; #if FUSION_BUILD_MULTI /* we need to fetch the whole map, otherwise a slave would try to */ for (i=desc->min_keycode; i<=desc->max_keycode; i++) get_keymap_entry( device, i ); #endif } static int make_id( DFBInputDeviceID prefered ) { int i; D_DEBUG_AT( Core_Input, "%s( 0x%02x )\n", __FUNCTION__, prefered ); D_ASSERT( core_input != NULL ); for (i=0; inum; i++) { CoreInputDevice *device = core_local->devices[i]; D_MAGIC_ASSERT( device, CoreInputDevice ); if (device->shared->id == prefered) return make_id( (prefered < DIDID_ANY) ? DIDID_ANY : (prefered + 1) ); } return prefered; } static DFBResult reload_keymap( CoreInputDevice *device ) { int i; InputDeviceShared *shared; D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); D_MAGIC_ASSERT( device, CoreInputDevice ); shared = device->shared; D_ASSERT( shared != NULL ); if (shared->device_info.desc.min_keycode < 0 || shared->device_info.desc.max_keycode < 0) return DFB_UNSUPPORTED; /* write -1 indicating entry is not fetched yet from driver */ for (i=0; ikeymap.num_entries; i++) shared->keymap.entries[i].code = -1; /* fetch the whole map */ for (i=shared->keymap.min_keycode; i<=shared->keymap.max_keycode; i++) get_keymap_entry( device, i ); D_INFO( "DirectFB/Input: Reloaded keymap for '%s' [0x%02x]\n", shared->device_info.desc.name, shared->id ); return DFB_OK; } static DFBResult set_sensitivity( CoreInputDevice *device, int sensitivity ) { InputDriver *driver; D_DEBUG_AT( Core_Input, "%s( %p, %d )\n", __FUNCTION__, device, sensitivity ); D_MAGIC_ASSERT( device, CoreInputDevice ); driver = device->driver; D_ASSERT( driver != NULL ); if (!driver->funcs->SetSensitivity) return DFB_UNSUPPORTED; return driver->funcs->SetSensitivity( device, device->driver_data, sensitivity ); } static FusionCallHandlerResult input_device_call_handler( int caller, /* fusion id of the caller */ int call_arg, /* optional call parameter */ void *call_ptr, /* optional call parameter */ void *ctx, /* optional handler context */ unsigned int serial, int *ret_val ) { CoreInputDeviceCommand command = call_arg; CoreInputDevice *device = ctx; D_DEBUG_AT( Core_Input, "%s( %d, %d, %p, %p )\n", __FUNCTION__, caller, call_arg, call_ptr, ctx ); D_MAGIC_ASSERT( device, CoreInputDevice ); switch (command) { case CIDC_RELOAD_KEYMAP: *ret_val = reload_keymap( device ); break; case CIDC_SET_SENSITIVITY: *ret_val = set_sensitivity( device, (long) call_ptr ); break; default: D_BUG( "unknown Core Input Device Command '%d'", command ); *ret_val = DFB_BUG; } return FCHR_RETURN; } static DFBResult init_axes( CoreInputDevice *device ) { int i, num; DFBResult ret; InputDeviceShared *shared; const InputDriverFuncs *funcs; D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( device->driver != NULL ); funcs = device->driver->funcs; D_ASSERT( funcs != NULL ); shared = device->shared; D_ASSERT( shared != NULL ); if (shared->device_info.desc.max_axis < 0) return DFB_OK; num = shared->device_info.desc.max_axis + 1; shared->axis_info = SHCALLOC( dfb_core_shmpool(device->core), num, sizeof(DFBInputDeviceAxisInfo) ); if (!shared->axis_info) return D_OOSHM(); shared->axis_num = num; if (funcs->GetAxisInfo) { for (i=0; iGetAxisInfo( device, device->driver_data, i, &shared->axis_info[i] ); if (ret) D_DERROR( ret, "Core/Input: GetAxisInfo() failed for '%s' [%d] on axis %d!\n", shared->device_info.desc.name, shared->id, i ); } } return DFB_OK; } static void init_drivers( CoreDFB *core ) { DirectLink *next; DirectModuleEntry *module; D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, core ); D_ASSERT( core_input != NULL ); direct_list_foreach_safe (module, next, dfb_input_modules.entries) { InputDriver *driver; const InputDriverFuncs *funcs; funcs = direct_module_ref( module ); if (!funcs) continue; driver = D_CALLOC( 1, sizeof(InputDriver) ); if (!driver) { D_OOM(); direct_module_unref( module ); continue; } D_ASSERT( funcs->GetDriverInfo != NULL ); funcs->GetDriverInfo( &driver->info ); driver->module = module; driver->funcs = funcs; direct_list_prepend( &core_local->drivers, &driver->link ); } } static DFBResult rescan_devices( CoreDFB *core ) { InputDriver *driver; FusionSHMPoolShared *pool = dfb_core_shmpool( core ); D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, core ); D_ASSERT( core_input != NULL ); direct_list_foreach (driver, core_local->drivers) { int i, num; const InputDriverFuncs *funcs = driver->funcs; D_DEBUG_AT( Core_Input, " -> probing '%s'...\n", driver->info.name ); num = funcs->GetAvailable(); D_DEBUG_AT( Core_Input, " -> %d available device(s) provided by '%s'.\n", num, driver->info.name ); for (i=driver->nr_devices; icore = core; memset( &device_info, 0, sizeof(InputDeviceInfo) ); device_info.desc.min_keycode = -1; device_info.desc.max_keycode = -1; D_MAGIC_SET( device, CoreInputDevice ); if (funcs->OpenDevice( device, i, &device_info, &driver_data )) { SHFREE( pool, shared ); D_MAGIC_CLEAR( device ); D_FREE( device ); continue; } D_DEBUG_AT( Core_Input, " -> opened '%s' (%d) %d.%d (%s)\n", device_info.desc.name, i + 1, driver->info.version.major, driver->info.version.minor, driver->info.vendor ); if (num > 1) snprintf( buf, sizeof(buf), "%s (%d)", device_info.desc.name, i+1 ); else snprintf( buf, sizeof(buf), "%s", device_info.desc.name ); /* init skirmish */ fusion_skirmish_init( &shared->lock, buf, dfb_core_world(core) ); /* create reactor */ shared->reactor = fusion_reactor_new( sizeof(DFBInputEvent), buf, dfb_core_world(core) ); fusion_reactor_set_lock( shared->reactor, &shared->lock ); /* init call */ fusion_call_init( &shared->call, input_device_call_handler, device, dfb_core_world(core) ); /* initialize shared data */ shared->id = make_id(device_info.prefered_id); shared->num = i; shared->device_info = device_info; shared->last_key = DIKI_UNKNOWN; shared->first_press = true; /* initialize local data */ device->shared = shared; device->driver = driver; device->driver_data = driver_data; D_INFO( "DirectFB/Input: %s %d.%d (%s)\n", buf, driver->info.version.major, driver->info.version.minor, driver->info.vendor ); if (device_info.desc.min_keycode > device_info.desc.max_keycode) { D_BUG("min_keycode > max_keycode"); device_info.desc.min_keycode = -1; device_info.desc.max_keycode = -1; } else if (device_info.desc.min_keycode >= 0 && device_info.desc.max_keycode >= 0) allocate_device_keymap( core, device ); init_axes( device ); /* add it to the list */ input_add_device( device ); } driver->nr_devices = num; } return DFB_OK; } static DFBInputDeviceKeymapEntry * get_keymap_entry( CoreInputDevice *device, int code ) { InputDeviceKeymap *map; DFBInputDeviceKeymapEntry *entry; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device != NULL ); D_ASSERT( device->shared != NULL ); map = &device->shared->keymap; /* safety check */ if (code < map->min_keycode || code > map->max_keycode) return NULL; /* point to right array index */ entry = &map->entries[code - map->min_keycode]; /* need to initialize? */ if (entry->code != code) { DFBResult ret; InputDriver *driver = device->driver; if (!driver) { D_BUG("seem to be a slave with an empty keymap"); return NULL; } /* write keycode to entry */ entry->code = code; /* fetch entry from driver */ ret = driver->funcs->GetKeymapEntry( device, device->driver_data, entry ); if (ret) return NULL; /* drivers may leave this blank */ if (entry->identifier == DIKI_UNKNOWN) entry->identifier = symbol_to_id( entry->symbols[DIKSI_BASE] ); if (entry->symbols[DIKSI_BASE_SHIFT] == DIKS_NULL) entry->symbols[DIKSI_BASE_SHIFT] = entry->symbols[DIKSI_BASE]; if (entry->symbols[DIKSI_ALT] == DIKS_NULL) entry->symbols[DIKSI_ALT] = entry->symbols[DIKSI_BASE]; if (entry->symbols[DIKSI_ALT_SHIFT] == DIKS_NULL) entry->symbols[DIKSI_ALT_SHIFT] = entry->symbols[DIKSI_ALT]; } return entry; } /* replace a single keymap entry with the code-entry pair */ static DFBResult set_keymap_entry( CoreInputDevice *device, int code, DFBInputDeviceKeymapEntry *entry ) { InputDeviceKeymap *map; D_ASSERT( device->shared != NULL ); D_ASSERT( device->shared->keymap.entries != NULL ); map = &device->shared->keymap; /* sanity check */ if (code < map->min_keycode || code > map->max_keycode) return DFB_FAILURE; /* copy the entry to the map */ map->entries[code - map->min_keycode] = *entry; return DFB_OK; } /* replace the complete current keymap with a keymap from a file. * the minimum-maximum keycodes of the driver are to be respected. */ static DFBResult load_keymap( CoreInputDevice *device, char *filename ) { DFBResult ret = DFB_OK; InputDeviceKeymap *map = 0; FILE *file = 0; DFBInputDeviceLockState lockstate = 0; D_ASSERT( device->shared != NULL ); D_ASSERT( device->shared->keymap.entries != NULL ); map = &device->shared->keymap; /* open the file */ file = fopen( filename, "r" ); if( !file ) { return errno2result( errno ); } /* read the file, line by line, and consume the mentioned scancodes */ while(1) { int i; int dummy; char buffer[201]; int keycode; char diki[201]; char diks[4][201]; char *b; DFBInputDeviceKeymapEntry entry = { .code = 0 }; b = fgets( buffer, 200, file ); if( !b ) { if( feof(file) ) { fclose(file); return DFB_OK; } fclose(file); return errno2result(errno); } /* comment or empty line */ if( buffer[0]=='#' || strcmp(buffer,"\n")==0 ) continue; /* check for lock state change */ if( !strncmp(buffer,"capslock:",9) ) { lockstate |= DILS_CAPS; continue; } if( !strncmp(buffer,":capslock",9) ) { lockstate &= ~DILS_CAPS; continue; } if( !strncmp(buffer,"numlock:",8) ) { lockstate |= DILS_NUM; continue; } if( !strncmp(buffer,":numlock",8) ) { lockstate &= ~DILS_NUM; continue; } i = sscanf( buffer, " keycode %i = %s = %s %s %s %s %i\n", &keycode, diki, diks[0], diks[1], diks[2], diks[3], &dummy ); if( i < 3 || i > 6 ) { /* we want 1 to 4 key symbols */ D_INFO( "DirectFB/Input: skipped erroneous input line %s\n", buffer ); continue; } if( keycode > map->max_keycode || keycode < map->min_keycode ) { D_INFO( "DirectFB/Input: skipped keycode %d out of range\n", keycode ); continue; } entry.code = keycode; entry.locks = lockstate; entry.identifier = lookup_keyidentifier( diki ); switch( i ) { case 6: entry.symbols[3] = lookup_keysymbol( diks[3] ); case 5: entry.symbols[2] = lookup_keysymbol( diks[2] ); case 4: entry.symbols[1] = lookup_keysymbol( diks[1] ); case 3: entry.symbols[0] = lookup_keysymbol( diks[0] ); /* fall through */ } switch( i ) { case 3: entry.symbols[1] = entry.symbols[0]; case 4: entry.symbols[2] = entry.symbols[0]; case 5: entry.symbols[3] = entry.symbols[1]; /* fall through */ } ret = set_keymap_entry( device, keycode, &entry ); if( ret ) return ret; } } static DFBInputDeviceKeySymbol lookup_keysymbol( char *symbolname ) { int i; /* we want uppercase */ for( i=0; i= 'a' && symbolname[i] <= 'z' ) symbolname[i] = symbolname[i] - 'a' + 'A'; for( i=0; i < sizeof (KeySymbolNames) / sizeof (KeySymbolNames[0]); i++ ) { if( strcmp( symbolname, KeySymbolNames[i].name ) == 0 ) return KeySymbolNames[i].symbol; } /* not found, maybe starting with 0x for raw conversion. * We are already at uppercase. */ if( symbolname[0]=='0' && symbolname[1]=='X' ) { int code=0; symbolname+=2; while(*symbolname) { if( *symbolname >= '0' && *symbolname <= '9' ) { code = code*16 + *symbolname - '0'; } else if( *symbolname >= 'A' && *symbolname <= 'F' ) { code = code*16 + *symbolname - 'A' + 10; } else { /* invalid character */ return DIKS_NULL; } symbolname++; } return code; } return DIKS_NULL; } static DFBInputDeviceKeyIdentifier lookup_keyidentifier( char *identifiername ) { int i; /* we want uppercase */ for( i=0; i= 'a' && identifiername[i] <= 'z' ) identifiername[i] = identifiername[i] - 'a' + 'A'; for( i=0; i < sizeof (KeyIdentifierNames) / sizeof (KeyIdentifierNames[0]); i++ ) { if( strcmp( identifiername, KeyIdentifierNames[i].name ) == 0 ) return KeyIdentifierNames[i].identifier; } return DIKI_UNKNOWN; } static bool lookup_from_table( CoreInputDevice *device, DFBInputEvent *event, DFBInputEventFlags lookup ) { DFBInputDeviceKeymapEntry *entry; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device != NULL ); D_ASSERT( device->shared != NULL ); D_ASSERT( event != NULL ); /* fetch the entry from the keymap, possibly calling the driver */ entry = get_keymap_entry( device, event->key_code ); if (!entry) return false; /* lookup identifier */ if (lookup & DIEF_KEYID) event->key_id = entry->identifier; /* lookup symbol */ if (lookup & DIEF_KEYSYMBOL) { DFBInputDeviceKeymapSymbolIndex index = (event->modifiers & DIMM_ALTGR) ? DIKSI_ALT : DIKSI_BASE; if (!(event->modifiers & DIMM_SHIFT) ^ !(entry->locks & event->locks)) index++; /* don't modify modifiers */ if (DFB_KEY_TYPE( entry->symbols[DIKSI_BASE] ) == DIKT_MODIFIER) event->key_symbol = entry->symbols[DIKSI_BASE]; else event->key_symbol = entry->symbols[index]; } return true; } static int find_key_code_by_id( CoreInputDevice *device, DFBInputDeviceKeyIdentifier id ) { int i; InputDeviceKeymap *map; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device != NULL ); D_ASSERT( device->shared != NULL ); map = &device->shared->keymap; for (i=0; inum_entries; i++) { DFBInputDeviceKeymapEntry *entry = &map->entries[i]; if (entry->identifier == id) return entry->code; } return -1; } static int find_key_code_by_symbol( CoreInputDevice *device, DFBInputDeviceKeySymbol symbol ) { int i; InputDeviceKeymap *map; D_MAGIC_ASSERT( device, CoreInputDevice ); D_ASSERT( core_input != NULL ); D_ASSERT( device != NULL ); D_ASSERT( device->shared != NULL ); map = &device->shared->keymap; for (i=0; inum_entries; i++) { int n; DFBInputDeviceKeymapEntry *entry = &map->entries[i]; for (n=0; n<=DIKSI_LAST; n++) if (entry->symbols[n] == symbol) return entry->code; } return -1; } #define FIXUP_KEY_FIELDS (DIEF_MODIFIERS | DIEF_LOCKS | \ DIEF_KEYCODE | DIEF_KEYID | DIEF_KEYSYMBOL) /* * Fill partially missing values for key_code, key_id and key_symbol by * translating those that are set. Fix modifiers/locks before if not set. * * * There are five valid constellations that give reasonable values. * (not counting the constellation where everything is set) * * Device has no translation table * 1. key_id is set, key_symbol not * -> key_code defaults to -1, key_symbol from key_id (up-translation) * 2. key_symbol is set, key_id not * -> key_code defaults to -1, key_id from key_symbol (down-translation) * * Device has a translation table * 3. key_code is set * -> look up key_id and/or key_symbol (key_code being the index) * 4. key_id is set * -> look up key_code and possibly key_symbol (key_id being searched for) * 5. key_symbol is set * -> look up key_code and key_id (key_symbol being searched for) * * Fields remaining will be set to the default, e.g. key_code to -1. */ static void fixup_key_event( CoreInputDevice *device, DFBInputEvent *event ) { int i; DFBInputEventFlags valid = event->flags & FIXUP_KEY_FIELDS; DFBInputEventFlags missing = valid ^ FIXUP_KEY_FIELDS; InputDeviceShared *shared = device->shared; D_MAGIC_ASSERT( device, CoreInputDevice ); /* Add missing flags */ event->flags |= missing; /* * Use cached values for modifiers/locks if they are missing. */ if (missing & DIEF_MODIFIERS) event->modifiers = shared->modifiers_l | shared->modifiers_r; if (missing & DIEF_LOCKS) event->locks = shared->locks; /* * With translation table */ if (device->shared->keymap.num_entries) { if (valid & DIEF_KEYCODE) { lookup_from_table( device, event, missing ); missing &= ~(DIEF_KEYID | DIEF_KEYSYMBOL); } else if (valid & DIEF_KEYID) { event->key_code = find_key_code_by_id( device, event->key_id ); if (event->key_code != -1) { lookup_from_table( device, event, missing ); missing &= ~(DIEF_KEYCODE | DIEF_KEYSYMBOL); } else if (missing & DIEF_KEYSYMBOL) { event->key_symbol = id_to_symbol( event->key_id, event->modifiers, event->locks ); missing &= ~DIEF_KEYSYMBOL; } } else if (valid & DIEF_KEYSYMBOL) { event->key_code = find_key_code_by_symbol( device, event->key_symbol ); if (event->key_code != -1) { lookup_from_table( device, event, missing ); missing &= ~(DIEF_KEYCODE | DIEF_KEYID); } else { event->key_symbol = symbol_to_id( event->key_symbol ); missing &= ~DIEF_KEYSYMBOL; } } } else { /* * Without translation table */ if (valid & DIEF_KEYID) { if (missing & DIEF_KEYSYMBOL) { event->key_symbol = id_to_symbol( event->key_id, event->modifiers, event->locks ); missing &= ~DIEF_KEYSYMBOL; } } else if (valid & DIEF_KEYSYMBOL) { event->key_id = symbol_to_id( event->key_symbol ); missing &= ~DIEF_KEYID; } } /* * Clear remaining fields. */ if (missing & DIEF_KEYCODE) event->key_code = -1; if (missing & DIEF_KEYID) event->key_id = DIKI_UNKNOWN; if (missing & DIEF_KEYSYMBOL) event->key_symbol = DIKS_NULL; /* * Update cached values for modifiers. */ if (DFB_KEY_TYPE(event->key_symbol) == DIKT_MODIFIER) { if (event->type == DIET_KEYPRESS) { switch (event->key_id) { case DIKI_SHIFT_L: shared->modifiers_l |= DIMM_SHIFT; break; case DIKI_SHIFT_R: shared->modifiers_r |= DIMM_SHIFT; break; case DIKI_CONTROL_L: shared->modifiers_l |= DIMM_CONTROL; break; case DIKI_CONTROL_R: shared->modifiers_r |= DIMM_CONTROL; break; case DIKI_ALT_L: shared->modifiers_l |= DIMM_ALT; break; case DIKI_ALT_R: shared->modifiers_r |= (event->key_symbol == DIKS_ALTGR) ? DIMM_ALTGR : DIMM_ALT; break; case DIKI_META_L: shared->modifiers_l |= DIMM_META; break; case DIKI_META_R: shared->modifiers_r |= DIMM_META; break; case DIKI_SUPER_L: shared->modifiers_l |= DIMM_SUPER; break; case DIKI_SUPER_R: shared->modifiers_r |= DIMM_SUPER; break; case DIKI_HYPER_L: shared->modifiers_l |= DIMM_HYPER; break; case DIKI_HYPER_R: shared->modifiers_r |= DIMM_HYPER; break; default: ; } } else { switch (event->key_id) { case DIKI_SHIFT_L: shared->modifiers_l &= ~DIMM_SHIFT; break; case DIKI_SHIFT_R: shared->modifiers_r &= ~DIMM_SHIFT; break; case DIKI_CONTROL_L: shared->modifiers_l &= ~DIMM_CONTROL; break; case DIKI_CONTROL_R: shared->modifiers_r &= ~DIMM_CONTROL; break; case DIKI_ALT_L: shared->modifiers_l &= ~DIMM_ALT; break; case DIKI_ALT_R: shared->modifiers_r &= (event->key_symbol == DIKS_ALTGR) ? ~DIMM_ALTGR : ~DIMM_ALT; break; case DIKI_META_L: shared->modifiers_l &= ~DIMM_META; break; case DIKI_META_R: shared->modifiers_r &= ~DIMM_META; break; case DIKI_SUPER_L: shared->modifiers_l &= ~DIMM_SUPER; break; case DIKI_SUPER_R: shared->modifiers_r &= ~DIMM_SUPER; break; case DIKI_HYPER_L: shared->modifiers_l &= ~DIMM_HYPER; break; case DIKI_HYPER_R: shared->modifiers_r &= ~DIMM_HYPER; break; default: ; } } /* write back to event */ if (missing & DIEF_MODIFIERS) event->modifiers = shared->modifiers_l | shared->modifiers_r; } /* * Update cached values for locks. */ if (event->type == DIET_KEYPRESS) { /* When we receive a new key press, toggle lock flags */ if (shared->first_press || shared->last_key != event->key_id) { switch (event->key_id) { case DIKI_CAPS_LOCK: shared->locks ^= DILS_CAPS; break; case DIKI_NUM_LOCK: shared->locks ^= DILS_NUM; break; case DIKI_SCROLL_LOCK: shared->locks ^= DILS_SCROLL; break; default: ; } } /* write back to event */ if (missing & DIEF_LOCKS) event->locks = shared->locks; /* store last pressed key */ shared->last_key = event->key_id; shared->first_press = false; } else if (event->type == DIET_KEYRELEASE) { shared->first_press = true; } /* Handle dead keys. */ if (DFB_KEY_TYPE(shared->last_symbol) == DIKT_DEAD) { for (i=0; ideadkey == shared->last_symbol) { for (i=0; map->combos[i].target; i++) { if (map->combos[i].target == event->key_symbol) { event->key_symbol = map->combos[i].result; break; } } break; } } if (event->type == DIET_KEYRELEASE && DFB_KEY_TYPE(event->key_symbol) != DIKT_MODIFIER) shared->last_symbol = event->key_symbol; } else shared->last_symbol = event->key_symbol; } static void fixup_mouse_event( CoreInputDevice *device, DFBInputEvent *event ) { InputDeviceShared *shared = device->shared; D_MAGIC_ASSERT( device, CoreInputDevice ); if (event->flags & DIEF_BUTTONS) { shared->buttons = event->buttons; } else { switch (event->type) { case DIET_BUTTONPRESS: shared->buttons |= (1 << event->button); break; case DIET_BUTTONRELEASE: shared->buttons &= ~(1 << event->button); break; default: ; } /* Add missing flag */ event->flags |= DIEF_BUTTONS; event->buttons = shared->buttons; } switch (event->type) { case DIET_AXISMOTION: if ((event->flags & DIEF_AXISABS) && event->axis >= 0 && event->axis < shared->axis_num) { if (!(event->flags & DIEF_MIN) && (shared->axis_info[event->axis].flags & DIAIF_ABS_MIN)) { event->min = shared->axis_info[event->axis].abs_min; event->flags |= DIEF_MIN; } if (!(event->flags & DIEF_MAX) && (shared->axis_info[event->axis].flags & DIAIF_ABS_MAX)) { event->max = shared->axis_info[event->axis].abs_max; event->flags |= DIEF_MAX; } } break; default: break; } } static DFBInputDeviceKeyIdentifier symbol_to_id( DFBInputDeviceKeySymbol symbol ) { if (symbol >= 'a' && symbol <= 'z') return DIKI_A + symbol - 'a'; if (symbol >= 'A' && symbol <= 'Z') return DIKI_A + symbol - 'A'; if (symbol >= '0' && symbol <= '9') return DIKI_0 + symbol - '0'; if (symbol >= DIKS_F1 && symbol <= DIKS_F12) return DIKI_F1 + symbol - DIKS_F1; switch (symbol) { case DIKS_ESCAPE: return DIKI_ESCAPE; case DIKS_CURSOR_LEFT: return DIKI_LEFT; case DIKS_CURSOR_RIGHT: return DIKI_RIGHT; case DIKS_CURSOR_UP: return DIKI_UP; case DIKS_CURSOR_DOWN: return DIKI_DOWN; case DIKS_ALTGR: return DIKI_ALT_R; case DIKS_CONTROL: return DIKI_CONTROL_L; case DIKS_SHIFT: return DIKI_SHIFT_L; case DIKS_ALT: return DIKI_ALT_L; case DIKS_META: return DIKI_META_L; case DIKS_SUPER: return DIKI_SUPER_L; case DIKS_HYPER: return DIKI_HYPER_L; case DIKS_TAB: return DIKI_TAB; case DIKS_ENTER: return DIKI_ENTER; case DIKS_SPACE: return DIKI_SPACE; case DIKS_BACKSPACE: return DIKI_BACKSPACE; case DIKS_INSERT: return DIKI_INSERT; case DIKS_DELETE: return DIKI_DELETE; case DIKS_HOME: return DIKI_HOME; case DIKS_END: return DIKI_END; case DIKS_PAGE_UP: return DIKI_PAGE_UP; case DIKS_PAGE_DOWN: return DIKI_PAGE_DOWN; case DIKS_CAPS_LOCK: return DIKI_CAPS_LOCK; case DIKS_NUM_LOCK: return DIKI_NUM_LOCK; case DIKS_SCROLL_LOCK: return DIKI_SCROLL_LOCK; case DIKS_PRINT: return DIKI_PRINT; case DIKS_PAUSE: return DIKI_PAUSE; case DIKS_BACKSLASH: return DIKI_BACKSLASH; case DIKS_PERIOD: return DIKI_PERIOD; case DIKS_COMMA: return DIKI_COMMA; default: ; } return DIKI_UNKNOWN; } static DFBInputDeviceKeySymbol id_to_symbol( DFBInputDeviceKeyIdentifier id, DFBInputDeviceModifierMask modifiers, DFBInputDeviceLockState locks ) { bool shift = !(modifiers & DIMM_SHIFT) ^ !(locks & DILS_CAPS); if (id >= DIKI_A && id <= DIKI_Z) return (shift ? DIKS_CAPITAL_A : DIKS_SMALL_A) + id - DIKI_A; if (id >= DIKI_0 && id <= DIKI_9) return DIKS_0 + id - DIKI_0; if (id >= DIKI_KP_0 && id <= DIKI_KP_9) return DIKS_0 + id - DIKI_KP_0; if (id >= DIKI_F1 && id <= DIKI_F12) return DIKS_F1 + id - DIKI_F1; switch (id) { case DIKI_ESCAPE: return DIKS_ESCAPE; case DIKI_LEFT: return DIKS_CURSOR_LEFT; case DIKI_RIGHT: return DIKS_CURSOR_RIGHT; case DIKI_UP: return DIKS_CURSOR_UP; case DIKI_DOWN: return DIKS_CURSOR_DOWN; case DIKI_CONTROL_L: case DIKI_CONTROL_R: return DIKS_CONTROL; case DIKI_SHIFT_L: case DIKI_SHIFT_R: return DIKS_SHIFT; case DIKI_ALT_L: case DIKI_ALT_R: return DIKS_ALT; case DIKI_META_L: case DIKI_META_R: return DIKS_META; case DIKI_SUPER_L: case DIKI_SUPER_R: return DIKS_SUPER; case DIKI_HYPER_L: case DIKI_HYPER_R: return DIKS_HYPER; case DIKI_TAB: return DIKS_TAB; case DIKI_ENTER: return DIKS_ENTER; case DIKI_SPACE: return DIKS_SPACE; case DIKI_BACKSPACE: return DIKS_BACKSPACE; case DIKI_INSERT: return DIKS_INSERT; case DIKI_DELETE: return DIKS_DELETE; case DIKI_HOME: return DIKS_HOME; case DIKI_END: return DIKS_END; case DIKI_PAGE_UP: return DIKS_PAGE_UP; case DIKI_PAGE_DOWN: return DIKS_PAGE_DOWN; case DIKI_CAPS_LOCK: return DIKS_CAPS_LOCK; case DIKI_NUM_LOCK: return DIKS_NUM_LOCK; case DIKI_SCROLL_LOCK: return DIKS_SCROLL_LOCK; case DIKI_PRINT: return DIKS_PRINT; case DIKI_PAUSE: return DIKS_PAUSE; case DIKI_KP_DIV: return DIKS_SLASH; case DIKI_KP_MULT: return DIKS_ASTERISK; case DIKI_KP_MINUS: return DIKS_MINUS_SIGN; case DIKI_KP_PLUS: return DIKS_PLUS_SIGN; case DIKI_KP_ENTER: return DIKS_ENTER; case DIKI_KP_SPACE: return DIKS_SPACE; case DIKI_KP_TAB: return DIKS_TAB; case DIKI_KP_EQUAL: return DIKS_EQUALS_SIGN; case DIKI_KP_DECIMAL: return DIKS_PERIOD; case DIKI_KP_SEPARATOR: return DIKS_COMMA; case DIKI_BACKSLASH: return DIKS_BACKSLASH; case DIKI_EQUALS_SIGN: return DIKS_EQUALS_SIGN; case DIKI_LESS_SIGN: return DIKS_LESS_THAN_SIGN; case DIKI_MINUS_SIGN: return DIKS_MINUS_SIGN; case DIKI_PERIOD: return DIKS_PERIOD; case DIKI_QUOTE_LEFT: case DIKI_QUOTE_RIGHT: return DIKS_QUOTATION; case DIKI_SEMICOLON: return DIKS_SEMICOLON; case DIKI_SLASH: return DIKS_SLASH; default: ; } return DIKS_NULL; } static void release_key( CoreInputDevice *device, DFBInputDeviceKeyIdentifier id ) { DFBInputEvent evt; D_MAGIC_ASSERT( device, CoreInputDevice ); evt.type = DIET_KEYRELEASE; if (DFB_KEY_TYPE(id) == DIKT_IDENTIFIER) { evt.flags = DIEF_KEYID; evt.key_id = id; } else { evt.flags = DIEF_KEYSYMBOL; evt.key_symbol = id; } dfb_input_dispatch( device, &evt ); } static void flush_keys( CoreInputDevice *device ) { D_MAGIC_ASSERT( device, CoreInputDevice ); if (device->shared->modifiers_l) { if (device->shared->modifiers_l & DIMM_ALT) release_key( device, DIKI_ALT_L ); if (device->shared->modifiers_l & DIMM_CONTROL) release_key( device, DIKI_CONTROL_L ); if (device->shared->modifiers_l & DIMM_HYPER) release_key( device, DIKI_HYPER_L ); if (device->shared->modifiers_l & DIMM_META) release_key( device, DIKI_META_L ); if (device->shared->modifiers_l & DIMM_SHIFT) release_key( device, DIKI_SHIFT_L ); if (device->shared->modifiers_l & DIMM_SUPER) release_key( device, DIKI_SUPER_L ); } if (device->shared->modifiers_r) { if (device->shared->modifiers_r & DIMM_ALTGR) release_key( device, DIKS_ALTGR ); if (device->shared->modifiers_r & DIMM_ALT) release_key( device, DIKI_ALT_R ); if (device->shared->modifiers_r & DIMM_CONTROL) release_key( device, DIKI_CONTROL_R ); if (device->shared->modifiers_r & DIMM_HYPER) release_key( device, DIKI_HYPER_R ); if (device->shared->modifiers_r & DIMM_META) release_key( device, DIKI_META_R ); if (device->shared->modifiers_r & DIMM_SHIFT) release_key( device, DIKI_SHIFT_R ); if (device->shared->modifiers_r & DIMM_SUPER) release_key( device, DIKI_SUPER_R ); } } static void dump_primary_layer_surface( CoreDFB *core ) { CoreLayer *layer = dfb_layer_at( DLID_PRIMARY ); CoreLayerContext *context; /* Get the currently active context. */ if (dfb_layer_get_active_context( layer, &context ) == DFB_OK) { CoreLayerRegion *region; /* Get the first region. */ if (dfb_layer_context_get_primary_region( context, false, ®ion ) == DFB_OK) { CoreSurface *surface; /* Lock the region to avoid tearing due to concurrent updates. */ dfb_layer_region_lock( region ); /* Get the surface of the region. */ if (dfb_layer_region_get_surface( region, &surface ) == DFB_OK) { /* Dump the surface contents. */ dfb_surface_dump_buffer( surface, CSBR_FRONT, dfb_config->screenshot_dir, "dfb" ); /* Release the surface. */ dfb_surface_unref( surface ); } /* Unlock the region. */ dfb_layer_region_unlock( region ); /* Release the region. */ dfb_layer_region_unref( region ); } /* Release the context. */ dfb_layer_context_unref( context ); } } static bool core_input_filter( CoreInputDevice *device, DFBInputEvent *event ) { D_MAGIC_ASSERT( device, CoreInputDevice ); if (dfb_system_input_filter( device, event )) return true; if (event->type == DIET_KEYPRESS) { switch (event->key_symbol) { case DIKS_PRINT: if (!event->modifiers && dfb_config->screenshot_dir) { dump_primary_layer_surface( device->core ); return true; } break; case DIKS_BACKSPACE: if (event->modifiers == DIMM_META) direct_trace_print_stacks(); break; case DIKS_ESCAPE: if (event->modifiers == DIMM_META) { #if FUSION_BUILD_MULTI DFBResult ret; CoreLayer *layer = dfb_layer_at( DLID_PRIMARY ); CoreLayerContext *context; /* Get primary (shared) context. */ ret = dfb_layer_get_primary_context( layer, false, &context ); if (ret) return false; /* Activate the context. */ dfb_layer_activate_context( layer, context ); /* Release the context. */ dfb_layer_context_unref( context ); #else kill( 0, SIGINT ); #endif return true; } break; default: break; } } return false; }