diff -r 000000000000 -r d54f32e146dd tactilefeedback/tactileclickplugin/src/tactileclickplugin.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tactilefeedback/tactileclickplugin/src/tactileclickplugin.cpp Thu Dec 17 08:53:38 2009 +0200 @@ -0,0 +1,375 @@ +/* +* Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: The click maker plugin, which +* handles key events at window server process. +* Part of: Tactile Feedback. +* +*/ + +#include +#include +#include + +#include "tactileclickplugin.h" +#include "OstTraceDefinitions.h" +#ifdef OST_TRACE_COMPILER_IN_USE +#include "tactileclickpluginTraces.h" +#endif + +// ======== MEMBER FUNCTIONS ======== + +CTactileClickPlugin::CTactileClickPlugin() + { + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +void CTactileClickPlugin::ConstructL() + { + TRACE( "CTactileClickPlugin::ConstructL - Begin" ); + + // Notice that we intentionally don't connect to feedback server here. + // This is because some players may try to connect to such servers, + // which don't exist yet when click plugin is loaded. + iAreaRegistry = CTactileAreaRegistry::NewL(); + + // We need to store ourselves to thead local storage, so that + // Anim Dll plugins can access the feedback functionality + Dll::SetTls( this ); + + TRACE( "CTactileClickPlugin::ConstructL - End" ); + } + +// --------------------------------------------------------------------------- +// We really have to trap ConstructL, because construction of click maker +// plug-in must not fail (otherwise WSERV will panic, resulting in KERN 4 and +// re-boot of whole device). +// --------------------------------------------------------------------------- +// +CTactileClickPlugin* CTactileClickPlugin::NewL() + { + CTactileClickPlugin* self = new( ELeave ) CTactileClickPlugin; + TRAP_IGNORE( self->ConstructL() ); + return self; + } + +// --------------------------------------------------------------------------- +// +// --------------------------------------------------------------------------- +// +CTactileClickPlugin::~CTactileClickPlugin() + { + delete iAreaRegistry; + iFeedback.Close(); + Dll::SetTls( NULL ); + } + +// --------------------------------------------------------------------------- +// From class CClickMaker. +// No implementation needed +// --------------------------------------------------------------------------- +// +void CTactileClickPlugin::KeyEvent( + TEventCode /*aType*/, const TKeyEvent& /*aEvent*/ ) + { + } + +// --------------------------------------------------------------------------- +// From class CClickMaker. +// No implementation needed +// --------------------------------------------------------------------------- +// +void CTactileClickPlugin::PointerEvent( const TPointerEvent& /*aEvent*/ ) + { + } + +// --------------------------------------------------------------------------- +// From class CClickMaker. +// +// Notice that we really have to check iFeedback handle and iAreaRegistry +// pointer here, because click maker construction must not fail +// (otherwise WSERV will panic) +// +// We handle three types of events here: +// +// 1. Pointer events coming from window server: For these we do hit testing, +// and use RTactileFeedback to play feedback accordingly. +// +// 2. Window group open events: These ones we pass to area registry for +// bookkeeping. +// +// 3. Window group close events: These ones we also pass to area registry, so +// that it can update its bookkeeping. +// --------------------------------------------------------------------------- +// +void CTactileClickPlugin::OtherEvent( TInt aType, TAny* aParam ) + { + // 1. Pointer events + if ( aParam && aType == EEventPointer && iFeedback.Handle() && iAreaRegistry ) + { + TPointerEventData* p = static_cast ( aParam ); + + // Extract pointer event from the data given by wserv + TPointerEvent pointerEvent = p->iPointerEvent; + + // Handle button down and button up events. + if ( pointerEvent.iType == TPointerEvent::EButton1Down || + pointerEvent.iType == TPointerEvent::EButton1Up ) + { + OstTrace0( TACTILE_PERFORMANCE, TACTILE_CLICK_PLUGIN_PEN_EVENT_1, "e_TACTILE_CLICK_PLUGIN_PEN_EVENT 1"); + + // Adjust position so that it is window -relative + pointerEvent.iPosition = ( p->iCurrentPos - p->iWindowOrigin ); + + TInt feedback = + iAreaRegistry->HitTestPointerEvent( + pointerEvent, + p->iWindowGroupId, + p->iClientHandle ); + + // There is extra vibra- and audio information in top two bits of + // feedback type. + TBool playVibra( EFalse ); + TBool playAudio( EFalse ); + + if ( pointerEvent.iType == TPointerEvent::EButton1Down ) + { + playVibra = ( ( feedback & KTactileVibraBitDown ) != 0); + playAudio = ( ( feedback & KTactileAudioBitDown ) != 0); + } + else + { + playVibra = ( ( feedback & KTactileVibraBitUp ) != 0); + playAudio = ( ( feedback & KTactileAudioBitUp ) != 0); + } + + // Clear upper two bytes completely + feedback &= 0xffff; + + if ( feedback != ETouchFeedbackNone ) + { + iFeedback.PlayFeedback( + static_cast( feedback ), + playVibra, + playAudio ); + } + + OstTrace0( TACTILE_PERFORMANCE, TACTILE_CLICK_PLUGIN_PEN_EVENT_0, "e_TACTILE_CLICK_PLUGIN_PEN_EVENT 0"); + } + } + // 2. Window group open events + else if ( aType == EEventGroupWindowOpen && iAreaRegistry ) + { + TGroupWindowOpenData* data = static_cast( aParam ); + + iAreaRegistry->HandleWindowGroupCreated( + data->iIdentifier, + data->iClient ); + } + // 3. Window group close events. + else if ( aType == EEventGroupWindowClose && iAreaRegistry ) + { + TInt identifier = reinterpret_cast( aParam ); + + iAreaRegistry->HandleWindowGroupClosed( + identifier ); + } + } + +// --------------------------------------------------------------------------- +// From class CClickMaker. +// This is run when client calls RSoundPlugin::CommandReply -function. +// +// Handling of individual commands has been moved to dedicated functions, +// because data handling requires some effort and relively complex code. +// This is due to the mistake in CClickMaker API design, as the data is +// not delivered in the same format as it was passed to RSoundPlugin on +// client side (client gives data in descriptor, but here the descriptor +// needs to be re-built from TAny* pointer, and in addition the lenght +// of data needs to be known based on command id). +// +// Leaving here causes RSoundPlugin::CommandReply to return with an error +// code on client side. It is thus important that we leave in case +// command ETactileOpCodeConnect fails, because that way client knows +// that feedback won't work and does not attempt to do updates in vain. +// --------------------------------------------------------------------------- +// +TInt CTactileClickPlugin::CommandReplyL( TInt aOpcode, TAny* aArgs ) + { + TRACE2( "CTactileClickPlugin::OtherEvent - Begin, opCode = %d", aOpcode ); + + TInt errCode = KErrNone; + + switch ( aOpcode ) + { + case ETactileOpCodeConnect: + HandleConnectL( aArgs ); + break; + case ETactileOpCodeDisconnect: + HandleDisconnect( aArgs ); + break; + case ETactileOpCodeImmediateFeedback: + errCode = HandleImmediateFeedback( aArgs ); + break; + default: + break; + } + + TRACE( "CTactileClickPlugin::OtherEvent - End" ); + + return errCode; + }; + +// --------------------------------------------------------------------------- +// From class MTactileFeedbackServer +// +// This function handles instant feedback requests originating inside +// window server (i.e. From Anim Dll plugins). +// --------------------------------------------------------------------------- +// +void CTactileClickPlugin::InstantFeedback( TTouchLogicalFeedback aType ) + { + TRACE( "CTactileClickPlugin::InstantFeedback - Begin" ); + + if ( iFeedback.Handle() ) + { + OstTrace0( TACTILE_PERFORMANCE, TACTILE_CLICK_PLUGIN_INSTANT_FEEDBACK_SERVER_API_1, "e_TACTILE_CLICK_PLUGIN_INSTANT_FEEDBACK_SERVER_API 1"); + + iFeedback.PlayFeedback( aType, ETrue, ETrue ); + + OstTrace0( TACTILE_PERFORMANCE, TACTILE_CLICK_PLUGIN_INSTANT_FEEDBACK_SERVER_API_0, "e_TACTILE_CLICK_PLUGIN_INSTANT_FEEDBACK_SERVER_API 0"); + } + } + +// --------------------------------------------------------------------------- +// Handling of connection requests from clients. +// +// #1 Try to connect to Tactile Feedback server in case it is not yet created, +// and creation has already been attempted (this is an optimization in case +// there is something wrong in the device so that construction cannot +// succeed). +// +// #2 Convert the data and pass connect .command to Area Registry +// +// #3 In case area registry or server connection does not exist, then leave +// so that client knows that feedback is not in use. +// --------------------------------------------------------------------------- +// +void CTactileClickPlugin::HandleConnectL( TAny* aArgs ) + { + // #1 Try to connct to RTactileFeedback first (if not yet connected) + if ( !iFeedback.Handle() ) + { + // Try to connect to Tactile Feedback server now when first client + // has connected. + User::LeaveIfError( iFeedback.Connect() ); + } + + // #2 + if ( aArgs && iAreaRegistry && iFeedback.Handle() ) + { + TInt* tmpInt = reinterpret_cast( aArgs ); + + TInt dataSize = sizeof( TTactileFeedbackConnectData ); + + TPtrC8 tmpConnectData( reinterpret_cast( tmpInt ), dataSize ); + + TTactileFeedbackConnectData clientData; + + TPckg dataBuf (clientData); + + dataBuf.Copy( tmpConnectData ); + + iAreaRegistry->HandleConnectL( clientData ); + } + else + { + // #3 Fail connection if everything is not in place. This way client + // will not waste effort doing updates in vain. + User::Leave( KErrGeneral ); + } + } + +// --------------------------------------------------------------------------- +// Handle disconnection requests from clients. +// +// Here we just convert the data and pass command to Area Registry +// --------------------------------------------------------------------------- +// +void CTactileClickPlugin::HandleDisconnect( TAny* aArgs ) + { + if ( aArgs && iAreaRegistry ) + { + TInt* tmpInt = reinterpret_cast( aArgs ); + + TInt dataSize = sizeof( TTactileFeedbackDisconnectData ); + + TPtrC8 tmpDisconnectData( reinterpret_cast( tmpInt ), dataSize ); + + TTactileFeedbackDisconnectData clientData; + + TPckg dataBuf (clientData); + + dataBuf.Copy( tmpDisconnectData ); + + iAreaRegistry->HandleDisconnect( clientData ); + } + } + +// --------------------------------------------------------------------------- +// Handling of immediate feedback, that originates from client application +// (See InstantFeedback function for handling of feedback that originates +// from inside window server) +// +// We don't need to do any state checks (call in progress) etc. here, +// because Feedback Server will do that anyway. Notice that we rely +// on the client API so that it does not send direct feedback in case client +// application has disabled feedback from itself. +// --------------------------------------------------------------------------- +// +TInt CTactileClickPlugin::HandleImmediateFeedback( TAny* aArgs ) + { + if ( aArgs && iFeedback.Handle() ) + { + TTactileFeedbackImmediateData* data = + reinterpret_cast( aArgs ); + + OstTrace0( TACTILE_PERFORMANCE, TACTILE_CLICK_PLUGIN_INSTANT_FEEDBACK_CLIENT_API_1, "e_TACTILE_CLICK_PLUGIN_INSTANT_FEEDBACK_CLIENT_API 1"); + + iFeedback.PlayFeedback( data->iFeedbackType, + data->iPlayVibra, + data->iPlayAudio ); + + OstTrace0( TACTILE_PERFORMANCE, TACTILE_CLICK_PLUGIN_INSTANT_FEEDBACK_CLIENT_API_0, "e_TACTILE_CLICK_PLUGIN_INSTANT_FEEDBACK_CLIENT_API 0"); + } + + return KErrNone; + } + +// ======== GLOBAL FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// Function with this signature needs to be the first exported function +// in click maker plugin DLLs. +// +// Constructs and returns an instance to tactile click maker plugin. +// --------------------------------------------------------------------------- +// +EXPORT_C CClickMaker* CreateClickMakerL() + { + TRACE( "CreateClickMakerL" ); + return CTactileClickPlugin::NewL(); + }