diff -r 2717213c588a -r 171fae344dd4 windowing/windowserver/nga/SERVER/EVENT.CPP --- a/windowing/windowserver/nga/SERVER/EVENT.CPP Tue Jun 22 15:21:29 2010 +0300 +++ b/windowing/windowserver/nga/SERVER/EVENT.CPP Fri Jul 16 11:45:55 2010 +0300 @@ -1,4 +1,4 @@ -// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 1994-2010 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" @@ -18,6 +18,7 @@ #include "EVENT.H" #include "W32STD.H" +#include #include #include #include "W32CLICK.H" @@ -32,12 +33,16 @@ #include "pointer.h" #include "debugbar.h" #include "advancedpointereventhelper.h" +#include "Graphics/wsgraphicdrawerinternal.h" GLREF_D CDebugLogBase *wsDebugLog; GLREF_C void StateDump(); GLREF_C void HeapDump(); +_LIT(KDefaultKeyRouterPluginName, "keyrouter.dll"); +_LIT(KWSERVIniFileVarKeyRouterPlugin, "KEYROUTERPLUGIN"); + #define IMPOSSIBLE 0xFFFFFFFF const TWsWinCmdCaptureKey ImpossibleKeyPress= @@ -160,6 +165,8 @@ TEventRequestQueue TWindowServerEvent::iScreenDeviceChangedQueue; TTime TWindowServerEvent::iPrevOomMessageTime; CCaptureKeys *TWindowServerEvent::iCaptureKeys; +CKeyEventRouter* TWindowServerEvent::iKeyEventRouter; +RLibrary TWindowServerEvent::iKeyEventRouterLibrary; CWsHotKey *TWindowServerEvent::iHotKeys; TInt TWindowServerEvent::iModifierState; CRawEventReceiver *TWindowServerEvent::iEventReceiver; @@ -172,12 +179,12 @@ TInt TWindowServerEvent::iEventHandlerCount=0; TRepeatKey CKeyboardRepeat::iCurrentRepeat; TRepeatKey CKeyboardRepeat::iAlternateRepeat; +TRepeatKey CKeyboardRepeat::iLongRepeat; TInt CKeyboardRepeat::iRepeatRollover=1; CKeyboardRepeat::TRepeatType CKeyboardRepeat::iRepeating=ERepeatNone; CKeyboardRepeat *CKeyboardRepeat::iThis=NULL; TTimeIntervalMicroSeconds32 CKeyboardRepeat::iInitialTime; TTimeIntervalMicroSeconds32 CKeyboardRepeat::iTime; -CWsWindowGroup *CKeyboardRepeat::iFocus=NULL; TBool CKeyboardRepeat::iAlternateRepeatExists=EFalse; CWsCaptureLongKey* CKeyboardRepeat::iLongCapture=NULL; @@ -198,6 +205,8 @@ { DeleteHotKeys(); delete iCaptureKeys; + delete iKeyEventRouter; + iKeyEventRouterLibrary.Close(); CKeyboardRepeat::Destroy(); delete iKeyTranslator; delete iEventReceiver; @@ -231,8 +240,57 @@ iKeyTranslator->ChangeKeyData(keyDataDllName); } + // CCaptureKeys is no longer used but a dummy object is required for + // calls to CKeyTranslator::TranslateKey() until capture functionality + // has been removed from ektran.dll. iCaptureKeys=new(ELeave) CCaptureKeys; iCaptureKeys->Construct(); + + // Load the key event routing plug-in. The DLL name may be overridden + // by setting the keyword KEYROUTERPLUGIN in wsini.ini. + TPtrC pluginName(KDefaultKeyRouterPluginName); + WsIniFile->FindVar(KWSERVIniFileVarKeyRouterPlugin, pluginName); + const TUidType uidType(KDynamicLibraryUid, KKeyRouterPluginUid); + TInt err = iKeyEventRouterLibrary.Load(pluginName, uidType); + + if (wsDebugLog) + { + TLogMessageText buf; + + if (err == KErrNone) + { + _LIT(KLogLoadOk, "Loaded plugin '%S' UID3 0x%x"); + const TFileName& pluginPathname = iKeyEventRouterLibrary.FileName(); + const TUid uid3 = iKeyEventRouterLibrary.Type()[2]; + buf.Format(KLogLoadOk, &pluginPathname, uid3.iUid); + } + else + { + _LIT(KLogLoadError, "Failed to load plugin '%S' (error %d)"); + buf.Format(KLogLoadError, &pluginName, err); + } + + wsDebugLog->MiscMessage(CDebugLogBase::ELogImportant, buf); + } + + if (err != KErrNone) + { +#ifdef _DEBUG + _LIT(KLoadError, "WServ: failed to load plugin '%S' (error %d)"); + RDebug::Print(KLoadError, &pluginName, err); +#endif + User::Leave(err); + } + + // Create the key event router + typedef CKeyEventRouter* (*TCreateFunc)(); + TCreateFunc newL = reinterpret_cast(iKeyEventRouterLibrary.Lookup(1)); + if (newL == NULL) + { + User::Leave(KErrNotFound); + } + iKeyEventRouter = (*newL)(); + for (TInt index=0;indexConstructLD(captureKey); // LinkHotKey(hotKey); @@ -622,6 +681,21 @@ TWsEvent event; event.SetType(EEventDisplayChanged); event.SetTimeNow(); + + // fill in the handle otherwise CONE will discard the notification + CWsObjectIx* clientObjList = aWsClient->ObjectIndex(); + const TWsObject* ptr=clientObjList->FirstObject(); + const TWsObject* end=ptr+clientObjList->Length(); + while(++ptriObject; + if (obj && obj->Type()==WS_HANDLE_GROUP_WINDOW) + { + event.SetHandle(ptr->iHandle); + break; + } + } + TWsDisplayChangedEvent* dispEvent = event.DisplayChanged(); dispEvent->iDisplayNumber = aDisplayNumber; dispEvent->iConfigurationChangeId = aConfigurationChangeId; @@ -641,23 +715,68 @@ aWin->EventQueue()->QueueEvent(aEvent, aPriority); } -void TWindowServerEvent::QueueKeyPress(const TKeyData& aKey, TInt aScanCode, CWsWindowGroup* aRepeatFocus, TBool aCheckRepeat,TInt aRepeats) +/** +Process a key press event. + +This function is called for every input key event and uses the Key Event +Routing plug-in to check for short and long key capture and determine the +destination window group for the queued event(s). +Window server hotkeys are also processed. +Note that the key repeat timer is started here but the key repeat events +generated by the timer go directly to QueueKeyPress(). + +@param aKeyEvent Input key event +@param aCheckRepeat Check for key repeat and long key capture +@param aRepeats Repeat count +*/ +void TWindowServerEvent::ProcessKeyPress(const TKeyEvent& aKeyEvent, TBool aCheckRepeat, TInt aRepeats) { - CWsWindowGroup* focusWin=CWsTop::FocusWindowGroup(); - TWsEvent event; - TKeyEvent& keyEvent=*event.Key(); - keyEvent.iCode=aKey.iKeyCode; - keyEvent.iScanCode=aScanCode; - keyEvent.iModifiers=aKey.iModifiers; - keyEvent.iRepeats=aRepeats; - if (!aRepeatFocus && CClick::IsHandler()) - CClick::KeyEvent(EEventKey,keyEvent); - CWsCaptureLongKey* longCapture=NULL; - if (aCheckRepeat) - longCapture=CWsCaptureLongKey::CheckForCapture(aKey.iKeyCode, aKey.iModifiers); - if (aKey.iIsCaptureKey) + CWsWindowGroup* focusWin = CWsTop::FocusWindowGroup(); + TUid focusAppUid = focusWin ? TUid::Uid(focusWin->Client()->SecureId().iId) : KNullUid; + + // Route the key event and check for short key capture. + // Note that the Key Routing plugin may translate or block key events. + TKeyEventRouterInput input(ECaptureTypeKey, aKeyEvent, focusWin, focusAppUid); + TKeyEventRouterOutput output; + +#ifdef _DEBUG + // RouteKey() must not fail. Check for leaves in case the plug-in + // is badly behaved. + TRAPD(err, iKeyEventRouter->RouteKey(input, output)); + WS_ASSERT_DEBUG(err == KErrNone, EWsPanicKeyEventRouterLeave); +#else + iKeyEventRouter->RouteKey(input, output); +#endif + + WS_ASSERT_DEBUG(output.iResult == ERouted || output.iResult == ECaptured || output.iResult == EConsumed, EWsPanicKeyEventRouterBadResult); + + if (output.iResult == EConsumed) { - if (aKey.iApp==NULL) // Captured by Wserv itself + focusWin = NULL; + } + else + { + focusWin = static_cast(output.iWindowGroup); + } + WS_ASSERT_DEBUG((focusWin == NULL || focusWin->Type() == WS_HANDLE_GROUP_WINDOW) && (output.iResult != ERouted || focusWin == CWsTop::FocusWindowGroup()), EWsPanicKeyEventRouterBadWindowGroup); + + // Ensure that short event is not marked with EModifierLongKey + output.iKeyEvent.iModifiers &= ~EModifierLongKey; + + // Generate key click unless the event is consumed. This is consistent + // with the behaviour when CKeyTranslator::TranslateKey() yields no + // translation for a particular scan code. (Click events for key up/down + // will still be generated by QueueKeyUpDown()). Note however that a long + // key press may still be captured even if the short event is consumed. + if (CClick::IsHandler() && output.iResult != EConsumed) + { + output.iKeyEvent.iRepeats = aRepeats; + CClick::KeyEvent(EEventKey, output.iKeyEvent); + } + + if (output.iResult == ECaptured) + { + if (output.iWindowGroup == NULL) // Captured by Wserv itself { _LIT(KWSERVDebugLogCapturedKey,"WSERV Captured Key"); CScreen* focusScreen=CWsTop::CurrentFocusScreen(); @@ -668,7 +787,7 @@ CWsHotKey *hotKey=iHotKeys; while(hotKey) { - if (hotKey->KeyHandle()==aKey.iHandle) + if (hotKey->KeyHandle() == reinterpret_cast(output.iCaptureHandle)) { switch(hotKey->HotKeyType()) { @@ -753,22 +872,85 @@ WS_PANIC_ALWAYS(EWsPanicUnknownCaptureKey); return; } - focusWin=((CWsWindowGroup *)aKey.iApp); + _LIT(KWSERVDebugLogKeyCapturedByApp,"Key captured by app %d"); if (wsDebugLog) wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything,KWSERVDebugLogKeyCapturedByApp,focusWin->Identifier()); if (CWsPassword::PasswordModeActive() && focusWin!=CWsPassword::PasswordWindow()->WinGroup()) return; } - if (aRepeatFocus && aRepeatFocus!=focusWin) - CKeyboardRepeat::CancelRepeat(NULL); // Repeat is going to different window so cancel it and don't deliver this key - else if (focusWin!=NULL && focusWin->CheckForPriorityKey(aKey,aScanCode)==EFalse) + + CWsCaptureLongKey* longCapture = NULL; + TKeyEventRouterOutput longOutput; + if (aCheckRepeat) { - if (longCapture || (aCheckRepeat && !aRepeatFocus && aKey.iModifiers&EModifierAutorepeatable)) + // Check for long key capture. + // Note that a long key event can only result from capture, there is + // no default detection or routing of long events. + input.iType = ECaptureTypeLongKey; +#ifdef _DEBUG + TRAPD(err, iKeyEventRouter->RouteKey(input, longOutput)); + WS_ASSERT_DEBUG(err == KErrNone, EWsPanicKeyEventRouterLeave); +#else + iKeyEventRouter->RouteKey(input, longOutput); +#endif + + if (longOutput.iResult == ECaptured) + { + longCapture = static_cast(longOutput.iCaptureHandle); + + // Mark long key events with EModifierLongKey so that applications + // can easily distinguish short and long events. + longOutput.iKeyEvent.iModifiers |= EModifierLongKey; + + // Start timer to detect long key press + CKeyboardRepeat::StartRepeat(aKeyEvent.iScanCode, output, &longOutput); + } + else if (output.iResult != EConsumed && output.iKeyEvent.iModifiers & EModifierAutorepeatable) { - if (CKeyboardRepeat::StartRepeat(aKey,aScanCode,focusWin,longCapture)) - return; + // Start timer for key repeat + CKeyboardRepeat::StartRepeat(aKeyEvent.iScanCode, output, NULL); } + } + + // Queue the short event + if (!longCapture || longCapture->iFlags & ELongCaptureShortEventImmediately) + { + QueueKeyPress(output, EFalse, aRepeats); + } + } + +/** +Queue a key press event. + +This function is called for each key event produced by ProcessKeyPress(), +for every key repeat and long key event generated by the timer and also for +delayed short key events from KeyUp(). + +@param aOutput Output key event from routing plug-in +@param aIsRepeat Event is due to key repeat +@param aRepeats Repeat count +*/ +void TWindowServerEvent::QueueKeyPress(const TKeyEventRouterOutput& aOutput, TBool aIsRepeat, TInt aRepeats) + { + if (aOutput.iResult == EConsumed) + { + // Don't deliver this key + return; + } + + TWsEvent event; + TKeyEvent& keyEvent = *event.Key(); + keyEvent = aOutput.iKeyEvent; + keyEvent.iRepeats = aRepeats; + + CWsWindowGroup* focusWin = static_cast(aOutput.iWindowGroup); + WS_ASSERT_DEBUG(focusWin == NULL || focusWin->Type() == WS_HANDLE_GROUP_WINDOW, EWsPanicKeyEventRouterBadWindowGroup); + + if (aIsRepeat && aOutput.iResult != ECaptured && focusWin != CWsTop::FocusWindowGroup()) + CKeyboardRepeat::CancelRepeat(NULL); // Repeat is going to different window so cancel it and don't deliver this key + else if (focusWin != NULL && focusWin->CheckForPriorityKey(keyEvent) == EFalse) + { event.SetType(EEventKey); event.SetHandle(focusWin->ClientHandle()); if (aRepeats!=0) @@ -776,18 +958,15 @@ CEventQueue* queue=focusWin->EventQueue(); queue->Wait(); const TWsEvent* prev=queue->PeekLastEvent(); - if (prev!=NULL && prev->Type()==EEventKey && prev->Key()->iRepeats>0) + if (prev != NULL && prev->Type() == EEventKey && prev->Key()->iRepeats > 0 && prev->Key()->iCode == keyEvent.iCode) { - event= *prev; - event.Key()->iRepeats+=aRepeats; - queue->UpdateLastEvent(event); + prev->Key()->iRepeats += aRepeats; queue->Signal(); if (CClick::IsHandler()) - CClick::KeyEvent(EEventKeyRepeat,*event.Key()); + CClick::KeyEvent(EEventKeyRepeat, *prev->Key()); return; } queue->Signal(); - event.Key()->iRepeats=aRepeats; if (CClick::IsHandler()) CClick::KeyEvent(EEventKeyRepeat,keyEvent); } @@ -795,24 +974,69 @@ } } +/** +Queue a key up/down event. + +@param aRawEvent Raw event +*/ void TWindowServerEvent::QueueKeyUpDown(const TRawEvent &aRawEvent) { - CWsWindowGroup *focusWin=CWsCaptureKeyUpsAndDowns::CheckForCapture(aRawEvent.ScanCode() __REMOVE_WINS_CHARCODE, iModifierState); - if (!focusWin) // If not captured - focusWin=CWsTop::FocusWindowGroup(); - TWsEvent event; - TEventCode type=aRawEvent.Type()==TRawEvent::EKeyUp ? EEventKeyUp : EEventKeyDown; - event.Key()->iCode=0; + TEventCode type = aRawEvent.Type() == TRawEvent::EKeyUp ? EEventKeyUp : EEventKeyDown; + + // Check for key up/down capture + TKeyEvent keyEvent; + keyEvent.iScanCode = aRawEvent.ScanCode() __REMOVE_WINS_CHARCODE; +#if defined(__WINS__) + keyEvent.iCode = __WINS_CHARCODE(aRawEvent.ScanCode()); +#else + keyEvent.iCode = 0; +#endif + keyEvent.iModifiers = iModifierState; + keyEvent.iRepeats = 0; + + CWsWindowGroup* focusWin = CWsTop::FocusWindowGroup(); + TUid focusAppUid = focusWin ? TUid::Uid(focusWin->Client()->SecureId().iId) : KNullUid; + + TKeyEventRouterInput input(ECaptureTypeKeyUpDown, keyEvent, focusWin, focusAppUid); + TKeyEventRouterOutput output; +#ifdef _DEBUG + TRAPD(err, iKeyEventRouter->RouteKey(input, output)); + WS_ASSERT_DEBUG(err == KErrNone, EWsPanicKeyEventRouterLeave); +#else + iKeyEventRouter->RouteKey(input, output); +#endif + + if (output.iResult == EConsumed) + { + // Don't deliver this key. A key click is still generated for the + // input event. + if (CClick::IsHandler()) + { + CClick::KeyEvent(type, keyEvent); + } + return; + } + WS_ASSERT_DEBUG(output.iResult == ERouted || output.iResult == ECaptured, EWsPanicKeyEventRouterBadResult); + + focusWin = static_cast(output.iWindowGroup); + WS_ASSERT_DEBUG((focusWin == NULL || focusWin->Type() == WS_HANDLE_GROUP_WINDOW) && (output.iResult != ERouted || focusWin == CWsTop::FocusWindowGroup()), EWsPanicKeyEventRouterBadWindowGroup); #if defined(__WINS__) if (focusWin && !focusWin->WsOwner()->RemoveKeyCode()) - event.Key()->iScanCode=aRawEvent.ScanCode(); - else + { + // Restore WINS character code + output.iKeyEvent.iScanCode |= output.iKeyEvent.iCode; + } + output.iKeyEvent.iCode = 0; #endif - event.Key()->iScanCode=aRawEvent.ScanCode() __REMOVE_WINS_CHARCODE; - event.Key()->iModifiers=iModifierState; - event.Key()->iRepeats=0; + + output.iKeyEvent.iRepeats = 0; if (CClick::IsHandler()) - CClick::KeyEvent(type,*event.Key()); + { + CClick::KeyEvent(type, output.iKeyEvent); + } + + TWsEvent event; + *event.Key() = output.iKeyEvent; if (focusWin!=NULL) { event.SetType(type); @@ -921,6 +1145,11 @@ } } +/* +Process a raw event + +@param aRawEvent Raw event +*/ void TWindowServerEvent::ProcessRawEvent(const TRawEvent& aRawEvent) // // Event has completed. @@ -1020,23 +1249,35 @@ case TRawEvent::EKeyDown: { _LIT(KWSERVDebugLogKeyDownArrival,"Key down arrives %d"); - if(CDebugBar* dbg = CWsTop::Screen()->DebugBar()) + CScreen* screen = CWsTop::Screen(); + WS_ASSERT_ALWAYS(screen, EWsPanicNoScreen); + if(CDebugBar* dbg = screen->DebugBar()) dbg->OnKeyEvent(); if (wsDebugLog) wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything,KWSERVDebugLogKeyDownArrival,aRawEvent.ScanCode()); CKeyboardRepeat::KeyDown(); TKeyData keyData; + // Note iCaptureKeys is needed as dummy arg only. Key capture is + // now handled in ProcessKeyPress(). TBool translated=iKeyTranslator->TranslateKey(aRawEvent.ScanCode(), EFalse,*iCaptureKeys,keyData); ProcessModifierChanges(); QueueKeyUpDown(aRawEvent); if (translated) - QueueKeyPress(keyData,aRawEvent.ScanCode() __REMOVE_WINS_CHARCODE,NULL,ETrue,0); + { + TKeyEvent keyEvent; + keyEvent.iScanCode = aRawEvent.ScanCode() __REMOVE_WINS_CHARCODE; + keyEvent.iCode = keyData.iKeyCode; + keyEvent.iModifiers = keyData.iModifiers; + ProcessKeyPress(keyEvent, ETrue, 0); + } } break; case TRawEvent::EKeyUp: { _LIT(KWSERVDebugLogKeyUpArrival,"Key up arrives %d"); - if(CDebugBar* dbg = CWsTop::Screen()->DebugBar()) + CScreen* screen = CWsTop::Screen(); + WS_ASSERT_ALWAYS(screen, EWsPanicNoScreen); + if(CDebugBar* dbg = screen->DebugBar()) dbg->OnKeyEvent(); if (wsDebugLog) wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything,KWSERVDebugLogKeyUpArrival,aRawEvent.ScanCode()); @@ -1048,7 +1289,11 @@ if (translated) { CKeyboardRepeat::CancelRepeat(NULL); - QueueKeyPress(keyData,aRawEvent.ScanCode() __REMOVE_WINS_CHARCODE,NULL,EFalse,0); + TKeyEvent keyEvent; + keyEvent.iScanCode = aRawEvent.ScanCode() __REMOVE_WINS_CHARCODE; + keyEvent.iCode = keyData.iKeyCode; + keyEvent.iModifiers = keyData.iModifiers; + ProcessKeyPress(keyEvent, EFalse, 0); } } break; @@ -1079,14 +1324,11 @@ _LIT(KWSERVDebugLogRepeatingKeyArrival,"Repeating key arrives %d"); if (wsDebugLog) wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything,KWSERVDebugLogRepeatingKeyArrival,aRawEvent.ScanCode()); - TKeyData keyData; - keyData.iModifiers=iKeyTranslator->GetModifierState(); - keyData.iApp=0; - keyData.iHandle=0; - keyData.iIsCaptureKey=EFalse; - keyData.iKeyCode=aRawEvent.ScanCode(); - iCaptureKeys->ProcessCaptureKeys(keyData); - QueueKeyPress(keyData, aRawEvent.ScanCode() __REMOVE_WINS_CHARCODE,NULL,EFalse,aRawEvent.Repeats()); + TKeyEvent keyEvent; + keyEvent.iScanCode = aRawEvent.ScanCode() __REMOVE_WINS_CHARCODE; + keyEvent.iCode = aRawEvent.ScanCode(); + keyEvent.iModifiers = iKeyTranslator->GetModifierState(); + ProcessKeyPress(keyEvent, EFalse, aRawEvent.Repeats()); } break; default: @@ -1096,33 +1338,26 @@ void TWindowServerEvent::ProcessKeyEvent(const TKeyEvent &aKeyEvent,TInt aRepeats) { - TKeyData keyData; - keyData.iModifiers=aKeyEvent.iModifiers; - keyData.iApp=0; - keyData.iHandle=0; - keyData.iIsCaptureKey=EFalse; - keyData.iKeyCode=aKeyEvent.iCode; if (CKeyboardRepeat::IsAreadyActive()) { CKeyboardRepeat::CancelRepeat(NULL); } - iCaptureKeys->ProcessCaptureKeys(keyData); - QueueKeyPress(keyData,aKeyEvent.iScanCode,NULL,aRepeats==0,aRepeats); + ProcessKeyPress(aKeyEvent, aRepeats == 0, aRepeats); } -void TWindowServerEvent::AddCaptureKeyL(const TCaptureKey &aCaptureKey) +void TWindowServerEvent::AddCaptureKeyL(const TKeyCaptureRequest& aRequest) { - iCaptureKeys->AddCaptureKeyL(aCaptureKey,aCaptureKey.iKeyCodePattern.iFiller); + iKeyEventRouter->AddCaptureKeyL(aRequest); } -void TWindowServerEvent::SetCaptureKey(TUint32 aHandle, const TCaptureKey &aCaptureKey) +void TWindowServerEvent::UpdateCaptureKeyL(const TKeyCaptureRequest& aRequest) { - iCaptureKeys->SetCaptureKey(aHandle, aCaptureKey,aCaptureKey.iKeyCodePattern.iFiller); + iKeyEventRouter->UpdateCaptureKeyL(aRequest); } -void TWindowServerEvent::CancelCaptureKey(TUint32 aHandle) +void TWindowServerEvent::CancelCaptureKey(TKeyCaptureType aType, TAny* aHandle) { - iCaptureKeys->CancelCaptureKey(aHandle); + iKeyEventRouter->CancelCaptureKey(aType, aHandle); } TInt TWindowServerEvent::GetModifierState() @@ -1463,21 +1698,27 @@ iTime=aTime; } +/** +Process timer events. + +Called when the key repeat timer expires, this function generates the +appropriate long key or repeated key event. If the timer was started for +normal key repeat or if the long key event was captured with the automatic +repeat option specified then the timer is restarted. +*/ void CKeyboardRepeat::RunL() { User::ResetInactivityTime(); - //WS_ASSERT_DEBUG(iRepeating!=ERepeatNone, EWsPanicTemp); + WS_ASSERT_DEBUG(iRepeating != ERepeatNone, EWsPanicKeyRepeat); TBool timer=ETrue; if (iRepeating>=ERepeatLong) { // Defensive programming - iLongCapture should never be NULL if iRepeating >= ERepeatLong + WS_ASSERT_DEBUG(iLongCapture != NULL, EWsPanicKeyRepeat); if (iLongCapture) { - iCurrentRepeat.iKey.iApp=REINTERPRET_CAST(TUint32,iLongCapture->iWindowGroup); - iCurrentRepeat.iKey.iHandle=0; - iCurrentRepeat.iKey.iIsCaptureKey=ETrue; - iCurrentRepeat.iKey.iKeyCode=iLongCapture->iData.outputKey; - timer=iLongCapture->iData.flags&ELongCaptureRepeatEvents; + iCurrentRepeat = iLongRepeat; + timer = iLongCapture->iFlags & ELongCaptureRepeatEvents; iRepeating=ERepeatLongRepeated; } else @@ -1491,53 +1732,67 @@ After(iTime); else iRepeating=ERepeatNone; - TWindowServerEvent::QueueKeyPress(iCurrentRepeat.iKey,iCurrentRepeat.iScanCode,iFocus,EFalse,1); + + TWindowServerEvent::QueueKeyPress(iCurrentRepeat.iOutput, ETrue, 1); } -TBool CKeyboardRepeat::StartRepeat(const TKeyData &aKey, TInt aScanCode, CWsWindowGroup *aRepeatFocus, CWsCaptureLongKey* aLongCapture) +/** +Start key repeat and long key press timer + +@param aInputScanCode Original scan code (before routing) +@param aShortEvent Short key event (routing plug-in output) +@param aLongEvent Pointer to long key event (routing plug-in output) + or NULL if none. + +Note: When aLongEvent != NULL, iCurrentRepeat reflects the short key event +until the timer has expired. This is necessary to allow a delayed short key +event to be delivered by KeyUp(). CancelRepeat() must therefore examine +iCurrentRepeat or iLongRepeat according to the repeat type in iRepeat. +*/ +void CKeyboardRepeat::StartRepeat(TInt aInputScanCode, const TKeyEventRouterOutput& aShortEvent, const TKeyEventRouterOutput* aLongEvent) { TTimeIntervalMicroSeconds32 time; - TBool ret=EFalse; - iCurrentRepeat.iScanCode=aScanCode; - iCurrentRepeat.iKey=aKey; + iCurrentRepeat.iInputScanCode = aInputScanCode; + iCurrentRepeat.iOutput = aShortEvent; - if (aLongCapture) + if (aLongEvent) { - iLongCapture=aLongCapture; - iRepeating=ERepeatLong; - time=aLongCapture->iData.delay; - ret=!(aLongCapture->iData.flags&ELongCaptureShortEventImmediately); - //need window group from long capture key or even better delete it altogether. - iFocus=aLongCapture->WindowGroup(); + iRepeating = ERepeatLong; + iLongRepeat.iInputScanCode = aInputScanCode; + iLongRepeat.iOutput = *aLongEvent; + iLongCapture = static_cast(aLongEvent->iCaptureHandle); + time = iLongCapture->iDelay; } else { - iFocus=aRepeatFocus; + iLongCapture = NULL; iRepeating=ERepeatNormal; time=iInitialTime; } iThis->After(time); - return ret; } +/** +Cancel key repeat processing +*/ void CKeyboardRepeat::doCancelRepeat() { iRepeating=ERepeatNone; iThis->Cancel(); } +/** +Cancel any key repeat associated with the specified window group + +@param aRepeatFocus Destination window group or NULL for all +*/ void CKeyboardRepeat::CancelRepeat(CWsWindowGroup *aRepeatFocus) { - if (aRepeatFocus==NULL || aRepeatFocus==iFocus) + if (iRepeating != ERepeatNone) { - if (iRepeating) - doCancelRepeat(); - iAlternateRepeatExists=EFalse; - } - else if (iRepeating >= ERepeatLong) - { - // Defensive programming - iLongCapture should never be NULL if iRepeating >= ERepeatLong - if (iLongCapture && iLongCapture->iWindowGroup == aRepeatFocus) + if (aRepeatFocus == NULL || + (iRepeating == ERepeatNormal) && (aRepeatFocus == iCurrentRepeat.iOutput.iWindowGroup) || + (iRepeating >= ERepeatLong) && (aRepeatFocus == iLongRepeat.iOutput.iWindowGroup)) { doCancelRepeat(); iAlternateRepeatExists=EFalse; @@ -1545,36 +1800,38 @@ } } -void CKeyboardRepeat::CancelRepeat(CWsWindowGroup *aRepeatFocus,TUint aScanCode,TBool aLongCaptureFlag,TUint aModifiers) +/** +Cancel any key repeat associated with the specified capture handle + +@param aCaptureHandle Handle to capture request +@param aLongCaptureFlag ETrue for long key capture, EFalse for normal key +*/ +void CKeyboardRepeat::CancelRepeat(const TAny* aCaptureHandle, TBool aLongCaptureFlag) { if (aLongCaptureFlag) { - // long capture key is cancelled - if (iRepeating >= ERepeatLong && iCurrentRepeat.iScanCode==aScanCode) - { - // Defensive programming - iLongCapture should never be NULL if iRepeating >= ERepeatLong - if (iLongCapture && aRepeatFocus == iLongCapture->iWindowGroup && - (aModifiers & iLongCapture->iData.modifierMask) == iLongCapture->iData.modifiers) - { - doCancelRepeat(); - iAlternateRepeatExists=EFalse; - } - } + // Cancel repeat for long capture key + if (iRepeating >= ERepeatLong && aCaptureHandle == iLongRepeat.iOutput.iCaptureHandle) + { + doCancelRepeat(); + iAlternateRepeatExists=EFalse; + } } else { - // normal capture key is cancelled - if (aRepeatFocus==iFocus) + // Cancel repeat for normal capture key + if (iRepeating == ERepeatNormal && aCaptureHandle == iCurrentRepeat.iOutput.iCaptureHandle) { - if (iRepeating>=ERepeatNormal && iCurrentRepeat.iScanCode==aScanCode) - { - doCancelRepeat(); - } + doCancelRepeat(); iAlternateRepeatExists=EFalse; } } } +/** +Process a key down event during key repeat. +The current repeat data is saved for possible restoration after rollover. +*/ void CKeyboardRepeat::KeyDown() { if (iRepeating!=ERepeatNone) @@ -1588,18 +1845,26 @@ } } +/** +Process a key up event during key repeat. +Send delayed short key event if necessary for long key event processing. +Switch to alternate repeat if rollover key was released. + +@param aScanCode Scan code +*/ void CKeyboardRepeat::KeyUp(TInt aScanCode) { - if (iAlternateRepeatExists && iAlternateRepeat.iScanCode==aScanCode) + if (iAlternateRepeatExists && iAlternateRepeat.iInputScanCode == aScanCode) iAlternateRepeatExists=EFalse; - if (iRepeating!=ERepeatNone && iCurrentRepeat.iScanCode==aScanCode) + if (iRepeating != ERepeatNone && iCurrentRepeat.iInputScanCode == aScanCode) { if (iRepeating==ERepeatLong) { // Defensive programming - iLongCapture should never be NULL if iRepeating >= ERepeatLong - if (iLongCapture && !(iLongCapture->iData.flags&ELongCaptureShortEventImmediately)) + WS_ASSERT_DEBUG(iLongCapture != NULL, EWsPanicKeyRepeat); + if (iLongCapture && !(iLongCapture->iFlags & ELongCaptureShortEventImmediately)) { - TWindowServerEvent::QueueKeyPress(iCurrentRepeat.iKey,iCurrentRepeat.iScanCode,NULL,EFalse,0); + TWindowServerEvent::QueueKeyPress(iCurrentRepeat.iOutput, EFalse, 0); } } if (iAlternateRepeatExists)