--- /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 <e32std.h>
+#include <tactilearearegistry.h>
+#include <tactilefeedbacktrace.h>
+
+#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<TPointerEventData*> ( 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<TTouchLogicalFeedback>( 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<TGroupWindowOpenData*>( aParam );
+
+ iAreaRegistry->HandleWindowGroupCreated(
+ data->iIdentifier,
+ data->iClient );
+ }
+ // 3. Window group close events.
+ else if ( aType == EEventGroupWindowClose && iAreaRegistry )
+ {
+ TInt identifier = reinterpret_cast<TInt>( 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<TInt*>( aArgs );
+
+ TInt dataSize = sizeof( TTactileFeedbackConnectData );
+
+ TPtrC8 tmpConnectData( reinterpret_cast<TUint8*>( tmpInt ), dataSize );
+
+ TTactileFeedbackConnectData clientData;
+
+ TPckg<TTactileFeedbackConnectData> 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<TInt*>( aArgs );
+
+ TInt dataSize = sizeof( TTactileFeedbackDisconnectData );
+
+ TPtrC8 tmpDisconnectData( reinterpret_cast<TUint8*>( tmpInt ), dataSize );
+
+ TTactileFeedbackDisconnectData clientData;
+
+ TPckg<TTactileFeedbackDisconnectData> 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<TTactileFeedbackImmediateData*>( 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();
+ }