diff --git a/widget/src/mac/nsMacEventHandler.cpp b/widget/src/mac/nsMacEventHandler.cpp index b7af1d2c893..c530073f3d2 100644 --- a/widget/src/mac/nsMacEventHandler.cpp +++ b/widget/src/mac/nsMacEventHandler.cpp @@ -50,6 +50,7 @@ #include "nsCarbonHelpers.h" #include "nsIRollupListener.h" #include "nsIMenuRollup.h" +#include "nsTSMStrategy.h" #ifndef RHAPSODY #include @@ -398,6 +399,10 @@ void nsMacEventDispatchHandler::NotifyDelete(void* aDeletedObject) #pragma mark - + +static PRBool gUseUnicodeAPI = PR_FALSE; +static PRBool gInitUseUnicodeAPI = PR_FALSE; + //------------------------------------------------------------------------- // // nsMacEventHandler constructor/destructor @@ -410,21 +415,27 @@ nsMacEventHandler::nsMacEventHandler(nsMacWindow* aTopLevelWidget) mTopLevelWidget = aTopLevelWidget; + nsTSMStrategy tsmstrategy; + // // create a TSMDocument for this window. We are allocating a TSM document for // each Mac window // mTSMDocument = nsnull; + if (tsmstrategy.UseUnicodeForInputMethod()) { + supportedServices[0] = kUnicodeDocument; + } else { supportedServices[0] = kTextService; - err = ::NewTSMDocument(1,supportedServices,&mTSMDocument,(long)this); - NS_ASSERTION(err==noErr,"nsMacEventHandler::nsMacEventHandler: NewTSMDocument failed."); + } + err = ::NewTSMDocument(1, supportedServices,&mTSMDocument, (long)this); + NS_ASSERTION(err==noErr, "nsMacEventHandler::nsMacEventHandler: NewTSMDocument failed."); #ifdef DEBUG_TSM - printf("nsMacEventHandler::nsMacEventHandler: created TSMDocument[%p]\n",mTSMDocument); + printf("nsMacEventHandler::nsMacEventHandler: created TSMDocument[%p]\n", mTSMDocument); #endif mIMEIsComposing = PR_FALSE; - mIMECompositionStr=nsnull; + mIMECompositionStr = nsnull; #if !TARGET_CARBON mControlActionProc = NewControlActionUPP(ScrollActionProc); @@ -865,13 +876,15 @@ static PRUint32 ConvertMacToRaptorKeyCode(UInt32 eventMessage, UInt32 eventModif // //------------------------------------------------------------------------- -void nsMacEventHandler::InitializeKeyEvent(nsKeyEvent& aKeyEvent, EventRecord& aOSEvent, nsWindow* focusedWidget, PRUint32 message) +void nsMacEventHandler::InitializeKeyEvent(nsKeyEvent& aKeyEvent, + EventRecord& aOSEvent, nsWindow* aFocusedWidget, PRUint32 aMessage, + PRBool* aIsChar, PRBool aConvertChar) { // // initalize the basic message parts // aKeyEvent.eventStructType = NS_KEY_EVENT; - aKeyEvent.message = message; + aKeyEvent.message = aMessage; aKeyEvent.point.x = 0; aKeyEvent.point.y = 0; aKeyEvent.time = PR_IntervalNow(); @@ -879,7 +892,7 @@ void nsMacEventHandler::InitializeKeyEvent(nsKeyEvent& aKeyEvent, EventRecord& a // // initalize the GUI event parts // - aKeyEvent.widget = focusedWidget; + aKeyEvent.widget = aFocusedWidget; aKeyEvent.nativeMsg = (void*)&aOSEvent; // @@ -893,36 +906,48 @@ void nsMacEventHandler::InitializeKeyEvent(nsKeyEvent& aKeyEvent, EventRecord& a // // nsKeyEvent parts // - if (message == NS_KEY_PRESS + if (aIsChar) + *aIsChar = PR_FALSE; + if (aMessage == NS_KEY_PRESS && !IsSpecialRaptorKey((aOSEvent.message & keyCodeMask) >> 8) ) { - if ( aKeyEvent.isControl ) + if (aKeyEvent.isControl) { + if (aIsChar) + *aIsChar = PR_TRUE; + if (aConvertChar) + { aKeyEvent.charCode = (aOSEvent.message & charCodeMask); - if ( aKeyEvent.charCode <= 26 ) + if (aKeyEvent.charCode <= 26) { - if ( aKeyEvent.isShift ) + if (aKeyEvent.isShift) aKeyEvent.charCode += 'A' - 1; else aKeyEvent.charCode += 'a' - 1; - } // if ( aKeyEvent.charCode <= 26 ) - + } // if (aKeyEvent.charCode <= 26) + } aKeyEvent.keyCode = 0; - } // if ( aKeyEvent.isControl ) - else // else for if ( aKeyEvent.isControl ) + } // if (aKeyEvent.isControl) + else // else for if (aKeyEvent.isControl) { - if ( !aKeyEvent.isMeta) + if (!aKeyEvent.isMeta) { aKeyEvent.isShift = aKeyEvent.isControl = aKeyEvent.isAlt = aKeyEvent.isMeta = 0; - } // if ( !aKeyEvent.isMeta) + } // if (!aKeyEvent.isMeta) aKeyEvent.keyCode = 0; + if (aIsChar) + *aIsChar = PR_TRUE; + if (aConvertChar) + { aKeyEvent.charCode = ConvertKeyEventToUnicode(aOSEvent); - if(aKeyEvent.isShift && aKeyEvent.charCode <= 'z' && aKeyEvent.charCode >= 'a') { + if (aKeyEvent.isShift && aKeyEvent.charCode <= 'z' && aKeyEvent.charCode >= 'a') + { aKeyEvent.charCode -= 32; } NS_ASSERTION(0 != aKeyEvent.charCode, "nsMacEventHandler::InitializeKeyEvent: ConvertKeyEventToUnicode returned 0."); - } // else for if ( aKeyEvent.isControl ) + } + } // else for if (aKeyEvent.isControl) } // if (message == NS_KEY_PRESS && !IsSpecialRaptorKey((aOSEvent.message & keyCodeMask) >> 8) ) else { @@ -933,14 +958,14 @@ void nsMacEventHandler::InitializeKeyEvent(nsKeyEvent& aKeyEvent, EventRecord& a // // obscure cursor if appropriate // - if ( message == NS_KEY_PRESS + if (aMessage == NS_KEY_PRESS && !aKeyEvent.isMeta && aKeyEvent.keyCode != NS_VK_PAGE_UP && aKeyEvent.keyCode != NS_VK_PAGE_DOWN // also consider: function keys and sole modifier keys ) { ::ObscureCursor(); - } // if ( message == NS_KEY_PRESS && !aKeyEvent.isMeta && aKeyEvent.keyCode != NS_VK_PAGE_UP && aKeyEvent.keyCode != NS_VK_PAGE_DOWN + } // if (message == NS_KEY_PRESS && !aKeyEvent.isMeta && aKeyEvent.keyCode != NS_VK_PAGE_UP && aKeyEvent.keyCode != NS_VK_PAGE_DOWN } @@ -1134,6 +1159,41 @@ PRBool nsMacEventHandler::HandleKeyEvent(EventRecord& aOSEvent) return result; } +//------------------------------------------------------------------------- +// +// HandleUKeyEvent +// +//------------------------------------------------------------------------- +PRBool nsMacEventHandler::HandleUKeyEvent(PRUnichar* text, long charCount, EventRecord& aOSEvent) +{ + nsresult result; + // get the focused widget + nsWindow* focusedWidget = gEventDispatchHandler.GetActive(); + if (!focusedWidget) + focusedWidget = mTopLevelWidget; + + // nsEvent + nsKeyEvent keyEvent; + PRBool isCharacter = PR_FALSE; + InitializeKeyEvent(keyEvent, aOSEvent, focusedWidget, NS_KEY_PRESS, &isCharacter, PR_FALSE); + if (isCharacter) + { + // it is a message with text, send all the unicode characters + PRUint32 i; + for (i = 0; i < charCount; i++) + { + keyEvent.charCode = text[i]; + result = focusedWidget->DispatchWindowEvent(keyEvent); + NS_ASSERTION(NS_SUCCEEDED(result), "cannot DispatchWindowEvent"); + } + } else { + // command / shift keys, etc. only send once + result = focusedWidget->DispatchWindowEvent(keyEvent); + NS_ASSERTION(NS_SUCCEEDED(result), "cannot DispatchWindowEvent"); + } + return result; +} + #pragma mark - //------------------------------------------------------------------------- // @@ -2075,6 +2135,196 @@ error: return res; } + +nsresult nsMacEventHandler::UnicodeHandleUpdateInputArea(PRUnichar* text, long charCount, + long fixedLength, TextRangeArray* textRangeList) +{ +#ifdef DEBUG_TSM + printf("********************************************************************************\n"); + printf("nsMacEventHandler::UnicodeHandleUpdateInputArea size=%d fixlen=%d\n",charCount, fixedLength); +#endif + nsresult res = NS_OK; + long committedLen = 0; + //------------------------------------------------------------------------------------------------ + // if we aren't in composition mode alredy, signal the backing store w/ the mode change + //------------------------------------------------------------------------------------------------ + if (!mIMEIsComposing) { + res = HandleStartComposition(); + NS_ASSERTION(NS_SUCCEEDED(res), "nsMacEventHandler::UnicodeHandleUpdateInputArea: HandleStartComposition failed."); + if (NS_FAILED(res)) + goto error; + } + // mIMECompositionStr should be created in the HandleStartComposition + NS_ASSERTION(mIMECompositionStr, "do not have mIMECompositionStr"); + if (nsnull == mIMECompositionStr) + { + res = NS_ERROR_OUT_OF_MEMORY; + goto error; + } + + //==================================================================================================== + // Note- It is possible that the UpdateInputArea event sent both committed text and uncommitted text + // at the same time. The easiest way to do that is using Korean input method w/ "Enter by Character" option + //==================================================================================================== + // 1. Handle the committed text + //==================================================================================================== + committedLen = (fixedLength == -1) ? charCount : fixedLength; + if (0 != committedLen) + { +#ifdef DEBUG_TSM + printf("Have commit text from 0 to %d\n", committedLen); +#endif + //------------------------------------------------------------------------------------------------ + // 1.1 send textEvent to commit the text + //------------------------------------------------------------------------------------------------ + mIMECompositionStr->Assign(text, committedLen); +#ifdef DEBUG_TSM + printf("1.2====================================\n"); +#endif + res = HandleTextEvent(0, nsnull); + NS_ASSERTION(NS_SUCCEEDED(res), "nsMacEventHandler::UnicodeHandleUpdateInputArea: HandleTextEvent failed."); + if (NS_FAILED(res)) + goto error; + //------------------------------------------------------------------------------------------------ + // 1.3 send compositionEvent to end the composition + //------------------------------------------------------------------------------------------------ + res = nsMacEventHandler::HandleEndComposition(); + NS_ASSERTION(NS_SUCCEEDED(res), "nsMacEventHandler::UnicodeHandleUpdateInputArea: HandleEndComposition failed."); + if (NS_FAILED(res)) + goto error; + } // 1. Handle the committed text + + //==================================================================================================== + // 2. Handle the uncommitted text + //==================================================================================================== + if ((-1 != fixedLength) && (charCount != fixedLength)) + { +#ifdef DEBUG_TSM + printf("Have new uncommitted text from %d to text_size(%d)\n", committedLen, charCount); +#endif + //------------------------------------------------------------------------------------------------ + // 2.1 send compositionEvent to start the composition + //------------------------------------------------------------------------------------------------ + // + // if we aren't in composition mode already, signal the backing store w/ the mode change + // + if (!mIMEIsComposing) { + res = HandleStartComposition(); + NS_ASSERTION(NS_SUCCEEDED(res), "nsMacEventHandler::UnicodeHandleUpdateInputArea: HandleStartComposition failed."); + if (NS_FAILED(res)) + goto error; + } // 2.1 send compositionEvent to start the composition + //------------------------------------------------------------------------------------------------ + // 2.2 send textEvent for the uncommitted text + //------------------------------------------------------------------------------------------------ + //------------------------------------------------------------------------------------------------ + // 2.2.1 make sure we have one range array + //------------------------------------------------------------------------------------------------ + + TextRangeArray rawTextRangeArray; + TextRangeArray *rangeArray; + if (textRangeList && textRangeList->fNumOfRanges) { + rangeArray = textRangeList; + } else { + rangeArray = &rawTextRangeArray; + rawTextRangeArray.fNumOfRanges = 1; + rawTextRangeArray.fRange[0].fStart = committedLen * 2; + rawTextRangeArray.fRange[0].fEnd = charCount * 2; + rawTextRangeArray.fRange[0].fHiliteStyle = NS_TEXTRANGE_RAWINPUT; + } + + +#ifdef DEBUG_TSM + printf("nsMacEventHandler::UnicodeHandleUpdateInputArea textRangeList is %s\n", textRangeList ? "NOT NULL" : "NULL"); +#endif + nsTextRangeArray xpTextRangeArray = new nsTextRange[rangeArray->fNumOfRanges]; + NS_ASSERTION(xpTextRangeArray!=NULL, "nsMacEventHandler::UnicodeHandleUpdateInputArea: xpTextRangeArray memory allocation failed."); + if (xpTextRangeArray == NULL) + { + res = NS_ERROR_OUT_OF_MEMORY; + goto error; + } + + //------------------------------------------------------------------------------------------------ + // 2.2.2 convert range array into our xp range array + //------------------------------------------------------------------------------------------------ + // + // the TEC offset mapping capabilities won't work here because you need to have unique, ordered offsets + // so instead we iterate over the range list and map each range individually. it's probably faster than + // trying to do collapse all the ranges into a single offset list + // + PRUint32 i; + for(i = 0; i < rangeArray->fNumOfRanges; i++) { + // 2.2.2.1 check each range item in NS_ASSERTION + NS_ASSERTION( + (NS_TEXTRANGE_CARETPOSITION==rangeArray->fRange[i].fHiliteStyle)|| + (NS_TEXTRANGE_RAWINPUT==rangeArray->fRange[i].fHiliteStyle)|| + (NS_TEXTRANGE_SELECTEDRAWTEXT==rangeArray->fRange[i].fHiliteStyle)|| + (NS_TEXTRANGE_CONVERTEDTEXT==rangeArray->fRange[i].fHiliteStyle)|| + (NS_TEXTRANGE_SELECTEDCONVERTEDTEXT==rangeArray->fRange[i].fHiliteStyle), + "illegal range type"); + NS_ASSERTION( rangeArray->fRange[i].fStart/2 <= charCount, "illegal range"); + NS_ASSERTION( rangeArray->fRange[i].fEnd/2 <= charCount, "illegal range"); + +#ifdef DEBUG_TSM + printf("nsMacEventHandler::UnicodeHandleUpdateInputArea textRangeList[%d] = (%d,%d) text_size = %d\n",i, + rangeArray->fRange[i].fStart/2, rangeArray->fRange[i].fEnd/2, charCount); +#endif + // 2.2.2.6 put destinationOffset into xpTextRangeArray[i].mStartOffset + xpTextRangeArray[i].mRangeType = rangeArray->fRange[i].fHiliteStyle; + xpTextRangeArray[i].mStartOffset = rangeArray->fRange[i].fStart / 2; + xpTextRangeArray[i].mEndOffset = rangeArray->fRange[i].fEnd / 2; + + // 2.2.2.7 Check the converted result in NS_ASSERTION +#ifdef DEBUG_TSM + printf("nsMacEventHandler::UnicodeHandleUpdateInputArea textRangeList[%d] => type=%d (%d,%d)\n",i, + xpTextRangeArray[i].mRangeType, + xpTextRangeArray[i].mStartOffset, xpTextRangeArray[i].mEndOffset); +#endif + + NS_ASSERTION((NS_TEXTRANGE_CARETPOSITION!=xpTextRangeArray[i].mRangeType) || + (xpTextRangeArray[i].mStartOffset == xpTextRangeArray[i].mEndOffset), + "start != end in CaretPosition"); + } + mIMECompositionStr->Assign(text+committedLen, charCount-committedLen); + //------------------------------------------------------------------------------------------------ + // 2.2.4 send the text event + //------------------------------------------------------------------------------------------------ +#ifdef DEBUG_TSM + printf("2.2.4====================================\n"); +#endif + + res = HandleTextEvent(rangeArray->fNumOfRanges,xpTextRangeArray); + NS_ASSERTION(NS_SUCCEEDED(res), "nsMacEventHandler::UnicodeHandleUpdateInputArea: HandleTextEvent failed."); + if (NS_FAILED(res)) + goto error; + delete [] xpTextRangeArray; + } // 2. Handle the uncommitted text + else if ((0==charCount) && (0==fixedLength)) + { + // 3. Handle empty text event + // This is needed when we input some uncommitted text, and then delete all of them + // When the last delete come, we will got a text_size = 0 and fixedLength = 0 + // In that case, we need to send a text event to clean up the input hole.... + mIMECompositionStr->AssignWithConversion(""); +#ifdef DEBUG_TSM + printf("3.====================================\n"); +#endif + // 3.1 send the empty text event. + res = HandleTextEvent(0, nsnull); + NS_ASSERTION(NS_SUCCEEDED(res),"nsMacEventHandler::UnicodeHandleUpdateInputArea: HandleTextEvent failed."); + if (NS_FAILED(res)) + goto error; + // 3.2 send an endComposition event, we need this to make sure the delete after this work properly. + res = nsMacEventHandler::HandleEndComposition(); + NS_ASSERTION(NS_SUCCEEDED(res),"nsMacEventHandler::UnicodeHandleUpdateInputArea: HandleEndComposition failed."); + if (NS_FAILED(res)) + goto error; + } + +error: + return res; +} //------------------------------------------------------------------------- // // HandleStartComposition diff --git a/widget/src/mac/nsMacEventHandler.h b/widget/src/mac/nsMacEventHandler.h index b8d603212ea..4594d71fffa 100644 --- a/widget/src/mac/nsMacEventHandler.h +++ b/widget/src/mac/nsMacEventHandler.h @@ -150,7 +150,9 @@ public: virtual long HandlePositionToOffset(Point aPoint,short* regionClass); virtual nsresult HandleOffsetToPosition(long offset,Point* position); virtual nsresult HandleUpdateInputArea(char* text,Size text_size, ScriptCode textScript,long fixedLength,TextRangeArray* textRangeArray); + virtual nsresult UnicodeHandleUpdateInputArea(PRUnichar* text, long charCount, long fixedLength,TextRangeArray* textRangeArray); virtual nsresult ResetInputState(); + virtual PRBool HandleUKeyEvent(PRUnichar* text, long charCount, EventRecord& aOSEvent); // // Synthetic events, generated internally to do things at specific times and @@ -162,7 +164,9 @@ public: protected: #if 1 - virtual void InitializeKeyEvent(nsKeyEvent& aKeyEvent, EventRecord& aOSEvent, nsWindow* focusedWidget, PRUint32 message); + virtual void InitializeKeyEvent(nsKeyEvent& aKeyEvent, EventRecord& aOSEvent, + nsWindow* aFocusedWidget, PRUint32 aMessage, + PRBool* aIsChar=nsnull, PRBool aConvertChar=PR_TRUE); virtual PRBool IsSpecialRaptorKey(UInt32 macKeyCode); virtual PRUint32 ConvertKeyEventToUnicode(EventRecord& aOSEvent); #endif @@ -194,7 +198,6 @@ protected: nsPoint mIMEPos; PRBool mIMEIsComposing; nsAutoString *mIMECompositionStr; - }; #endif // MacMacEventHandler_h__ diff --git a/widget/src/mac/nsMacTSMMessagePump.cpp b/widget/src/mac/nsMacTSMMessagePump.cpp index caabc14c23f..f463e25e4b2 100644 --- a/widget/src/mac/nsMacTSMMessagePump.cpp +++ b/widget/src/mac/nsMacTSMMessagePump.cpp @@ -41,6 +41,8 @@ #include "nsString.h" #include #include +#include +#include "nsTSMStrategy.h" #include "nsCarbonHelpers.h" @@ -54,6 +56,7 @@ AEEventHandlerUPP nsMacTSMMessagePump::mPos2OffsetUPP = NULL; AEEventHandlerUPP nsMacTSMMessagePump::mOffset2PosUPP = NULL; AEEventHandlerUPP nsMacTSMMessagePump::mUpdateUPP = NULL; +AEEventHandlerUPP nsMacTSMMessagePump::mKeyboardUPP = NULL; //------------------------------------------------------------------------- // @@ -63,24 +66,37 @@ AEEventHandlerUPP nsMacTSMMessagePump::mUpdateUPP = NULL; nsMacTSMMessagePump::nsMacTSMMessagePump() { OSErr err; + nsTSMStrategy tsmstrategy; mPos2OffsetUPP = NewAEEventHandlerUPP(nsMacTSMMessagePump::PositionToOffsetHandler); - NS_ASSERTION(mPos2OffsetUPP!=NULL,"nsMacTSMMessagePump::InstallTSMAEHandlers: NewAEEventHandlerUPP[Pos2Pffset] failed"); + NS_ASSERTION(mPos2OffsetUPP!=NULL, "nsMacTSMMessagePump::InstallTSMAEHandlers: NewAEEventHandlerUPP[Pos2Pffset] failed"); mOffset2PosUPP = NewAEEventHandlerUPP(nsMacTSMMessagePump::OffsetToPositionHandler); - NS_ASSERTION(mPos2OffsetUPP!=NULL,"nsMacTSMMessagePump::InstallTSMAEHandlers: NewAEEventHandlerUPP[Pos2Pffset] failed"); + NS_ASSERTION(mPos2OffsetUPP!=NULL, "nsMacTSMMessagePump::InstallTSMAEHandlers: NewAEEventHandlerUPP[Pos2Pffset] failed"); + if (tsmstrategy.UseUnicodeForInputMethod()) { + mUpdateUPP = NewAEEventHandlerUPP(nsMacTSMMessagePump::UnicodeUpdateHandler); + } else { mUpdateUPP = NewAEEventHandlerUPP(nsMacTSMMessagePump::UpdateHandler); - NS_ASSERTION(mPos2OffsetUPP!=NULL,"nsMacTSMMessagePump::InstallTSMAEHandlers: NewAEEventHandlerUPP[Pos2Pffset] failed"); + } + NS_ASSERTION(mPos2OffsetUPP!=NULL, "nsMacTSMMessagePump::InstallTSMAEHandlers: NewAEEventHandlerUPP[Pos2Pffset] failed"); - err = AEInstallEventHandler(kTextServiceClass,kPos2Offset,mPos2OffsetUPP,(long)this,false); - NS_ASSERTION(err==noErr,"nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Pos2Offset] failed"); + err = AEInstallEventHandler(kTextServiceClass, kPos2Offset, mPos2OffsetUPP, (long)this, false); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Pos2Offset] failed"); - err = AEInstallEventHandler(kTextServiceClass,kOffset2Pos,mOffset2PosUPP,(long)this,false); - NS_ASSERTION(err==noErr,"nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Offset2Pos] failed"); + err = AEInstallEventHandler(kTextServiceClass, kOffset2Pos, mOffset2PosUPP, (long)this, false); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Offset2Pos] failed"); - err = AEInstallEventHandler(kTextServiceClass,kUpdateActiveInputArea,mUpdateUPP,(long)this,false); - NS_ASSERTION(err==noErr,"nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Update] failed"); + err = AEInstallEventHandler(kTextServiceClass, kUpdateActiveInputArea, mUpdateUPP, (long)this, false); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Update] failed"); + + if (tsmstrategy.UseUnicodeForKeyboard()) { + mKeyboardUPP = NewAEEventHandlerUPP(nsMacTSMMessagePump::UnicodeNotFromInputMethodHandler); + NS_ASSERTION(mKeyboardUPP!=NULL, "nsMacTSMMessagePump::InstallTSMAEHandlers: NewAEEventHandlerUPP[FromInputMethod] failed"); + + err = AEInstallEventHandler(kTextServiceClass, kUnicodeNotFromInputMethod, mKeyboardUPP, (long)this, false); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[FromInputMethod] failed"); + } } @@ -88,36 +104,44 @@ nsMacTSMMessagePump::~nsMacTSMMessagePump() { OSErr err; - err = AERemoveEventHandler(kTextServiceClass,kPos2Offset,mPos2OffsetUPP,false); - NS_ASSERTION(err==noErr,"nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Pos2Offset] failed"); + err = AERemoveEventHandler(kTextServiceClass, kPos2Offset, mPos2OffsetUPP, false); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Pos2Offset] failed"); - err = AERemoveEventHandler(kTextServiceClass,kOffset2Pos,mOffset2PosUPP,false); - NS_ASSERTION(err==noErr,"nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Offset2Pos] failed"); + err = AERemoveEventHandler(kTextServiceClass, kOffset2Pos, mOffset2PosUPP, false); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Offset2Pos] failed"); - err = AERemoveEventHandler(kTextServiceClass,kUpdateActiveInputArea,mUpdateUPP,false); - NS_ASSERTION(err==noErr,"nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Update] failed"); + err = AERemoveEventHandler(kTextServiceClass, kUpdateActiveInputArea, mUpdateUPP, false); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[Update] failed"); ::DisposeAEEventHandlerUPP(mPos2OffsetUPP); ::DisposeAEEventHandlerUPP(mOffset2PosUPP); ::DisposeAEEventHandlerUPP(mUpdateUPP); + nsTSMStrategy tsmstrategy; + if (tsmstrategy.UseUnicodeForKeyboard()) { + err = AERemoveEventHandler(kTextServiceClass, kUnicodeNotFromInputMethod, mKeyboardUPP, false); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandlers[FromInputMethod] failed"); + ::DisposeAEEventHandlerUPP(mKeyboardUPP); + } + } + //------------------------------------------------------------------------- nsMacTSMMessagePump* nsMacTSMMessagePump::gSingleton = nsnull; //------------------------------------------------------------------------- nsMacTSMMessagePump* nsMacTSMMessagePump::GetSingleton() { - if(nsnull == gSingleton) + if (nsnull == gSingleton) { gSingleton = new nsMacTSMMessagePump(); - NS_ASSERTION(gSingleton!=NULL,"nsMacTSMMessagePump::GetSingleton: Unable to create TSM Message Pump."); + NS_ASSERTION(gSingleton!=NULL, "nsMacTSMMessagePump::GetSingleton: Unable to create TSM Message Pump."); } return gSingleton; } //------------------------------------------------------------------------- void nsMacTSMMessagePump::Shutdown() { - if(gSingleton) { + if (gSingleton) { delete gSingleton; gSingleton = nsnull; } @@ -143,36 +167,36 @@ pascal OSErr nsMacTSMMessagePump::PositionToOffsetHandler(const AppleEvent *theA // Extract the nsMacEventHandler for this TSMDocument. It's stored as the TSMDocument's // refcon // - err = AEGetParamPtr(theAppleEvent,keyAETSMDocumentRefcon,typeLongInteger,&returnedType, - &eventHandler,sizeof(eventHandler),&actualSize); - NS_ASSERTION(err==noErr,"nsMacTSMMessagePump::PositionToOffsetHandler: AEGetParamPtr[TSMRefcon] failed"); + err = AEGetParamPtr(theAppleEvent, keyAETSMDocumentRefcon, typeLongInteger, &returnedType, + &eventHandler, sizeof(eventHandler), &actualSize); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::PositionToOffsetHandler: AEGetParamPtr[TSMRefcon] failed"); if (err!=noErr) return err; // // Extract the Position parameter. // - err = AEGetParamPtr(theAppleEvent,keyAECurrentPoint,typeQDPoint,&returnedType, - &thePoint,sizeof(thePoint),&actualSize); - NS_ASSERTION(err==noErr,"nsMacTSMMessagePump::PositionToOffsetHandler: AGGetParamPtr[Point] failed"); + err = AEGetParamPtr(theAppleEvent, keyAECurrentPoint, typeQDPoint, &returnedType, + &thePoint, sizeof(thePoint), &actualSize); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::PositionToOffsetHandler: AGGetParamPtr[Point] failed"); if (err!=noErr) return err; // // pass the request to the widget system // - offset = eventHandler->HandlePositionToOffset(thePoint,®ionClass); + offset = eventHandler->HandlePositionToOffset(thePoint, ®ionClass); // // build up the AE reply (need offset and region class) // - err = AEPutParamPtr(reply,keyAEOffset,typeLongInteger,&offset,sizeof(offset)); - NS_ASSERTION(err==noErr,"nsMacTSMMessagePump::PositionToOffsetHandler: AEPutParamPtr failed"); + err = AEPutParamPtr(reply, keyAEOffset, typeLongInteger, &offset, sizeof(offset)); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::PositionToOffsetHandler: AEPutParamPtr failed"); if (err!=noErr) return err; - err = AEPutParamPtr(reply,keyAERegionClass,typeShortInteger,®ionClass,sizeof(regionClass)); - NS_ASSERTION(err==noErr,"nsMacTSMMessagePump::PositionToOffsetHandler: AEPutParamPtr failed"); + err = AEPutParamPtr(reply, keyAERegionClass, typeShortInteger, ®ionClass, sizeof(regionClass)); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::PositionToOffsetHandler: AEPutParamPtr failed"); if (err!=noErr) return err; @@ -191,34 +215,34 @@ pascal OSErr nsMacTSMMessagePump::OffsetToPositionHandler(const AppleEvent *theA // // Extract the nsMacEvenbtHandler for this TSMDocument. It's stored as the refcon. // - err = AEGetParamPtr(theAppleEvent,keyAETSMDocumentRefcon,typeLongInteger,&returnedType, - &eventHandler,sizeof(eventHandler),&actualSize); - NS_ASSERTION(err==noErr,"nsMacTSMMessagePump::OffsetToPositionHandler: AEGetParamPtr[TSMRefcon] failed."); + err = AEGetParamPtr(theAppleEvent, keyAETSMDocumentRefcon, typeLongInteger, &returnedType, + &eventHandler, sizeof(eventHandler), &actualSize); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::OffsetToPositionHandler: AEGetParamPtr[TSMRefcon] failed."); if (err!=noErr) return err; // // Extract the Offset parameter // - err = AEGetParamPtr(theAppleEvent,keyAEOffset,typeLongInteger,&returnedType, - &offset,sizeof(offset),&actualSize); - NS_ASSERTION(err==noErr,"nsMacTSMMessagePump::PositionToOffsetHandler: AEGetParamPtr[Offset] failed."); + err = AEGetParamPtr(theAppleEvent, keyAEOffset, typeLongInteger, &returnedType, + &offset, sizeof(offset), &actualSize); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::PositionToOffsetHandler: AEGetParamPtr[Offset] failed."); if (err!=noErr) return err; // // Pass the OffsetToPosition request to the widgets to handle // - res = eventHandler->HandleOffsetToPosition(offset,&thePoint); - NS_ASSERTION(NS_SUCCEEDED(res),"nsMacMessagePup::PositionToOffsetHandler: OffsetToPosition handler failed."); + res = eventHandler->HandleOffsetToPosition(offset, &thePoint); + NS_ASSERTION(NS_SUCCEEDED(res), "nsMacMessagePup::PositionToOffsetHandler: OffsetToPosition handler failed."); if (NS_FAILED(res)) return paramErr; // // build up the reply (point) // - err = AEPutParamPtr(reply,keyAEPoint,typeQDPoint,&thePoint,sizeof(Point)); - NS_ASSERTION(err==noErr,"nsMacTSMMessagePump::PositionToOffsetHandler: AEPutParamPtr[Point][ failed."); + err = AEPutParamPtr(reply, keyAEPoint, typeQDPoint, &thePoint, sizeof(Point)); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::PositionToOffsetHandler: AEPutParamPtr[Point] failed."); if (err!=noErr) return err; @@ -240,17 +264,17 @@ pascal OSErr nsMacTSMMessagePump::UpdateHandler(const AppleEvent *theAppleEvent, // // refcon stores the nsMacEventHandler // - err = AEGetParamPtr(theAppleEvent,keyAETSMDocumentRefcon,typeLongInteger,&returnedType, - &eventHandler,sizeof(eventHandler),&actualSize); - NS_ASSERTION(err==noErr,"nsMacTSMMessagePump::UpdateHandler: AEGetParamPtr[TSMRefcon] failed."); + err = AEGetParamPtr(theAppleEvent, keyAETSMDocumentRefcon, typeLongInteger, &returnedType, + &eventHandler, sizeof(eventHandler), &actualSize); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::UpdateHandler: AEGetParamPtr[TSMRefcon] failed."); if (err!=noErr) return err; // // IME update text // - err = AEGetParamDesc(theAppleEvent,keyAETheData,typeChar,&text); - NS_ASSERTION(err==noErr,"nsMacTSMMessagePump::UpdateHandler: AEGetParamDesc[Text] failed."); + err = AEGetParamDesc(theAppleEvent, keyAETheData, typeChar, &text); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::UpdateHandler: AEGetParamDesc[Text] failed."); if (err!=noErr) return err; @@ -259,8 +283,8 @@ pascal OSErr nsMacTSMMessagePump::UpdateHandler(const AppleEvent *theAppleEvent, // textScript=smUninterp; AEDesc slr; - err = AEGetParamDesc(theAppleEvent,keyAETSMScriptTag,typeIntlWritingCode,&slr); - NS_ASSERTION(err==noErr,"nsMacTSMMessagePump::UpdateHandler: AEGetParamDesc[keyAETSMScriptTag] failed."); + err = AEGetParamDesc(theAppleEvent, keyAETSMScriptTag, typeIntlWritingCode, &slr); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::UpdateHandler: AEGetParamDesc[keyAETSMScriptTag] failed."); if (err!=noErr) return err; @@ -279,24 +303,24 @@ pascal OSErr nsMacTSMMessagePump::UpdateHandler(const AppleEvent *theAppleEvent, // // length of converted text // - err = AEGetParamPtr(theAppleEvent,keyAEFixLength,typeLongInteger,&returnedType, - &fixLength,sizeof(fixLength),&actualSize); - NS_ASSERTION(err==noErr,"nsMacTSMMessagePump::UpdateHandler: AEGetParamPtr[fixlen] failed."); + err = AEGetParamPtr(theAppleEvent, keyAEFixLength, typeLongInteger, &returnedType, + &fixLength, sizeof(fixLength), &actualSize); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::UpdateHandler: AEGetParamPtr[fixlen] failed."); if (err!=noErr) return err; // // extract the hilite ranges (optional param) // - err = AEGetParamDesc(theAppleEvent,keyAEHiliteRange,typeTextRangeArray,&hiliteRangeArray); - NS_ASSERTION(err==noErr||err==errAEDescNotFound,"nsMacTSMMessagePump::UpdateHandler: AEGetParamPtr[fixlen] failed."); + err = AEGetParamDesc(theAppleEvent, keyAEHiliteRange, typeTextRangeArray, &hiliteRangeArray); + NS_ASSERTION(err==noErr||err==errAEDescNotFound, "nsMacTSMMessagePump::UpdateHandler: AEGetParamPtr[fixlen] failed."); if (err==errAEDescNotFound) { hiliteRangePtr=NULL; } else if (err==noErr) { #if TARGET_CARBON Size hiliteRangeSize = ::AEGetDescDataSize(&hiliteRangeArray); hiliteRangePtr = (TextRangeArray *) NewPtr(hiliteRangeSize); - if(!hiliteRangePtr) + if (!hiliteRangePtr) return MemError(); err = AEGetDescData(&hiliteRangeArray, (void *) hiliteRangePtr, hiliteRangeSize); if (err!=noErr) { @@ -327,16 +351,16 @@ pascal OSErr nsMacTSMMessagePump::UpdateHandler(const AppleEvent *theAppleEvent, Size text_size = ::GetHandleSize(text.dataHandle); mbcsText.SetCapacity(text_size+1); char* mbcsTextPtr = (char*)mbcsText.get(); - strncpy(mbcsTextPtr,*(text.dataHandle),text_size); + strncpy(mbcsTextPtr, *(text.dataHandle), text_size); mbcsTextPtr[text_size]=0; #endif // // must pass HandleUpdateInputArea a null-terminated multibyte string, the text size must include the terminator // - res = eventHandler->HandleUpdateInputArea(mbcsTextPtr,text_size,textScript,fixLength,hiliteRangePtr); + res = eventHandler->HandleUpdateInputArea(mbcsTextPtr, text_size, textScript, fixLength, hiliteRangePtr); - NS_ASSERTION(NS_SUCCEEDED(res),"nsMacMessagePump::UpdateHandler: HandleUpdated failed."); + NS_ASSERTION(NS_SUCCEEDED(res), "nsMacMessagePump::UpdateHandler: HandleUpdated failed."); if (NS_FAILED(res)) err = paramErr; @@ -344,10 +368,10 @@ pascal OSErr nsMacTSMMessagePump::UpdateHandler(const AppleEvent *theAppleEvent, // clean up // #if TARGET_CARBON - if(hiliteRangePtr) + if (hiliteRangePtr) DisposePtr((Ptr) hiliteRangePtr); #else - if(hiliteRangePtr) + if (hiliteRangePtr) ::HUnlock(hiliteRangeArray.dataHandle); #endif @@ -356,3 +380,187 @@ pascal OSErr nsMacTSMMessagePump::UpdateHandler(const AppleEvent *theAppleEvent, return noErr; } + +static OSErr GetAppleEventTSMData(const AppleEvent *inAE, nsMacEventHandler **outEventHandler, AEDesc *outText) +{ + *outEventHandler = nsnull; + //*outText = nsnull; + + // + // refcon stores the nsMacEventHandler + // + DescType returnedType; + Size actualSize; + OSErr err = ::AEGetParamPtr(inAE, keyAETSMDocumentRefcon, typeLongInteger, &returnedType, + outEventHandler, sizeof(nsMacEventHandler *), &actualSize); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::GetAppleEventTSMData: AEGetParamPtr[TSMRefcon] failed."); + if (err) + return err; + + // + // get text + // + err = ::AEGetParamDesc(inAE, keyAETheData, typeUnicodeText, outText); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::GetAppleEventTSMData: AEGetParamDesc[Text] failed."); + return err; +} + +static OSErr AETextToString(AEDesc &aAEDesc, nsString& aOutString, Size& text_size) +{ + OSErr err = noErr; + PRUnichar* unicodeTextPtr; + text_size = 0; + aOutString.Truncate(0); + +#if TARGET_CARBON + text_size = ::AEGetDescDataSize(&aAEDesc) / 2; + aOutString.SetLength(text_size + 1); + unicodeTextPtr = (PRUnichar*)aOutString.get(); + err = AEGetDescData(&aAEDesc, (void *) unicodeTextPtr, text_size * 2); + if (err!=noErr) + return err; +#else + text_size = ::GetHandleSize(aAEDesc.dataHandle) / 2; + aOutString.SetLength(text_size + 1); + unicodeTextPtr = (PRUnichar*)aOutString.get(); + nsCRT::memcpy(unicodeTextPtr, *(aAEDesc.dataHandle), text_size * 2); +#endif + + unicodeTextPtr[text_size ] = PRUnichar('\0'); // null terminate it. + return noErr; +} + + + +pascal OSErr nsMacTSMMessagePump::UnicodeUpdateHandler(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon) +{ + OSErr err = noErr; + DescType returnedType; + nsMacEventHandler* eventHandler; + Size actualSize; + AEDesc text, hiliteRangeArray; + long fixLength; + nsresult res; + TextRangeArray* hiliteRangePtr; + + err = GetAppleEventTSMData(theAppleEvent, &eventHandler, &text); + if (err) + return err; + + // + // length of converted text + // + err = ::AEGetParamPtr(theAppleEvent, keyAEFixLength, typeLongInteger, &returnedType, + &fixLength, sizeof(fixLength), &actualSize); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::UnicodeUpdateHandler: AEGetParamPtr[fixlen] failed."); + if (err) + return err; + + // + // extract the hilite ranges (optional param) + // + err = ::AEGetParamDesc(theAppleEvent, keyAEHiliteRange, typeTextRangeArray, &hiliteRangeArray); + NS_ASSERTION(err==noErr||err==errAEDescNotFound, "nsMacTSMMessagePump::UnicodeUpdateHandler: AEGetParamDesc[hiliteRangeArray] failed."); + if (errAEDescNotFound == err) + { + hiliteRangePtr = NULL; + } + else if (noErr == err) + { +#if TARGET_CARBON + Size hiliteRangeSize = ::AEGetDescDataSize(&hiliteRangeArray); + hiliteRangePtr = (TextRangeArray *) NewPtr(hiliteRangeSize); + if (!hiliteRangePtr) + { + err = MemError(); + goto err2; + } + err = ::AEGetDescData(&hiliteRangeArray, (void *)hiliteRangePtr, hiliteRangeSize); + if (noErr != err) + { + goto err1; + } +#else + ::HLock(hiliteRangeArray.dataHandle); + hiliteRangePtr = (TextRangeArray*)*(hiliteRangeArray.dataHandle); +#endif + } + else + { + goto err3; + } + + // grab the text now + { + nsAutoString unicodeText; + Size text_size; + err = AETextToString(text, unicodeText, text_size); + if (noErr == err) + { + res = eventHandler->UnicodeHandleUpdateInputArea((PRUnichar*)unicodeText.get(), text_size, fixLength / 2, hiliteRangePtr); + NS_ASSERTION(NS_SUCCEEDED(res), "nsMacMessagePump::UnicodeUpdateHandler: HandleUpdated failed."); + if (NS_FAILED(res)) + err = paramErr; + // fall to cleanup below + } + } + + // + // clean up + // +err1: +#if TARGET_CARBON + if (hiliteRangePtr) + ::DisposePtr((Ptr)hiliteRangePtr); +#else + if (hiliteRangePtr) + ::HUnlock(hiliteRangeArray.dataHandle); +#endif + +err2: + (void)::AEDisposeDesc(&hiliteRangeArray); +err3: + (void)::AEDisposeDesc(&text); + + return err; +} + +pascal OSErr nsMacTSMMessagePump::UnicodeNotFromInputMethodHandler(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon) +{ + OSErr err; + nsMacEventHandler* eventHandler; + AEDesc text; + DescType returnedType; + Size actualSize; + EventRecord event; + + err = GetAppleEventTSMData(theAppleEvent, &eventHandler, &text); + if (err != noErr) + return err; + + err = ::AEGetParamPtr(theAppleEvent, keyAETSMEventRecord, typeLowLevelEventRecord, &returnedType, + &event, sizeof(event), &actualSize); + NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::UnicodeNotFromInputMethodHandler: AEGetParamPtr[event] failed."); + if (noErr != err) + { + (void)::AEDisposeDesc(&text); + return err; + } + + nsAutoString unicodeText; + Size text_size; + err = AETextToString(text, unicodeText, text_size); + if (noErr == err) + { + nsresult res; + res = eventHandler->HandleUKeyEvent((PRUnichar*)unicodeText.get(), text_size, event); + NS_ASSERTION(NS_SUCCEEDED(res), "nsMacMessagePump::UnicodeNotFromInputMethodHandler: HandleUpdated failed."); + if (NS_FAILED(res)) { + err = paramErr; + // fall to cleanup below + } + } + + (void)::AEDisposeDesc(&text); + return err; +} diff --git a/widget/src/mac/nsMacTSMMessagePump.h b/widget/src/mac/nsMacTSMMessagePump.h index d5992d8f855..9bf6a936bb1 100644 --- a/widget/src/mac/nsMacTSMMessagePump.h +++ b/widget/src/mac/nsMacTSMMessagePump.h @@ -63,9 +63,12 @@ private: static pascal OSErr PositionToOffsetHandler(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon); static pascal OSErr OffsetToPositionHandler(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon); static pascal OSErr UpdateHandler(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon); + static pascal OSErr UnicodeUpdateHandler(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon); + static pascal OSErr UnicodeNotFromInputMethodHandler(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon); static AEEventHandlerUPP mPos2OffsetUPP; static AEEventHandlerUPP mOffset2PosUPP; static AEEventHandlerUPP mUpdateUPP; + static AEEventHandlerUPP mKeyboardUPP; static nsMacTSMMessagePump* gSingleton;