Back to index

lightning-sunbird  0.9+nobinonly
CTextInputEventHandling.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is the Mozilla browser.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications, Inc.
00020  * Portions created by the Initial Developer are Copyright (C) 1999
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Frank Yung-Fong Tang <ftang@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 /*
00040  * The embedding application could choose to install either Carbon Event Handler 
00041  * or Apple Event to implement Asian Input Method and/or Unicode keyboard mapping.
00042  *
00043  * This file is a sample implementation of how ot use Carbon Text Input event handler 
00044  * that. Example of Apple event handler could be found at nsMacTSMMessagePump.{h,cpp}
00045  */ 
00046  
00047 #include "CTextInputEventHandler.h"
00048 #include "nsCRT.h"
00049 #include "nsAutoBuffer.h"
00050 
00051 #pragma mark -
00052 
00053 #pragma mark -
00054 
00055 
00056 //*************************************************************************************
00057 //  GetGeckoTarget
00058 //*************************************************************************************
00059 CBrowserShell* CTextInputEventHandler::GetGeckoTarget()
00060 {
00061   return dynamic_cast<CBrowserShell*> (LCommander::GetTarget());  
00062 }
00063 
00064 #pragma mark -
00065 
00066 //*************************************************************************************
00067 //  GetScriptLang
00068 //*************************************************************************************
00069 OSStatus CTextInputEventHandler::GetScriptLang(EventRef inEvent, ScriptLanguageRecord& outSlr )
00070 {
00071   OSStatus err = ::GetEventParameter(inEvent, kEventParamTextInputSendSLRec, typeIntlWritingCode, NULL, 
00072                           sizeof(outSlr), NULL, &outSlr);
00073   return err;
00074 }
00075 
00076 //*************************************************************************************
00077 //  GetText
00078 //*************************************************************************************
00079 OSStatus CTextInputEventHandler::GetText(EventRef inEvent, nsString& outString)
00080 {
00081   UInt32 neededSize;
00082   outString.Truncate(0);
00083   OSStatus err = ::GetEventParameter(inEvent, kEventParamTextInputSendText, typeUnicodeText, NULL, 0, &neededSize, NULL);
00084   if (noErr != err)
00085     return err;
00086     
00087   if (neededSize > 0) 
00088   {
00089     nsAutoBuffer<PRUnichar, 256> buf;
00090     if (! buf.EnsureElemCapacity(neededSize/sizeof(PRUnichar)))
00091       return eventParameterNotFoundErr;
00092 
00093     err = ::GetEventParameter(inEvent, kEventParamTextInputSendText, typeUnicodeText, NULL, 
00094                             neededSize, &neededSize, buf.get());
00095                             
00096     if (noErr == err) 
00097        outString.Assign(buf.get(), neededSize/sizeof(PRUnichar));
00098   }
00099   return err;
00100 }
00101 
00102 #pragma mark -
00103 
00104 
00105 //*************************************************************************************
00106 //  HandleUnicodeForKeyEvent
00107 //*************************************************************************************
00108 OSStatus CTextInputEventHandler::HandleUnicodeForKeyEvent(
00109   CBrowserShell* aBrowserShell, 
00110   EventHandlerCallRef inHandlerCallRef, 
00111   EventRef inEvent)
00112 {
00113   NS_ENSURE_TRUE(aBrowserShell, eventNotHandledErr);
00114   EventRef keyboardEvent;
00115   OSStatus err = ::GetEventParameter(inEvent, kEventParamTextInputSendKeyboardEvent, typeEventRef, NULL, 
00116                           sizeof(keyboardEvent), NULL, &keyboardEvent);
00117   
00118   if (noErr != err)
00119     return eventParameterNotFoundErr;
00120   
00121   // Check first to see if the key event is a cmd-key or control-key.
00122   // If so, return eventNotHandledErr, and the keydown event will end
00123   // up being handled by LEventDispatcher::EventKeyDown() which is the
00124   // standard PowerPlant handling.
00125   UInt32 keyModifiers;  
00126   err = ::GetEventParameter(keyboardEvent, kEventParamKeyModifiers, typeUInt32,
00127         NULL, sizeof(UInt32), NULL, &keyModifiers);
00128   if ((noErr == err) && (keyModifiers & (cmdKey | controlKey)))
00129     return eventNotHandledErr;
00130     
00131   EventRecord eventRecord;                        
00132                        
00133   if (! ::ConvertEventRefToEventRecord(keyboardEvent, &eventRecord))
00134     return eventParameterNotFoundErr;
00135   // printf("uk1- %d %d %d %d %d\n", eventRecord.what, eventRecord.message, eventRecord.when, eventRecord.where, eventRecord.modifiers);
00136 
00137   ScriptLanguageRecord slr;
00138   err = GetScriptLang(inEvent, slr);
00139   if (noErr != err)
00140     return eventParameterNotFoundErr;
00141   
00142   nsAutoString text;
00143   err = GetText(inEvent, text);
00144   if (noErr != err)
00145     return eventParameterNotFoundErr;
00146   
00147   // printf("call HandleUnicodeForKeyEvent textlength = %d script=%d language=%d\n",  text.Length(), slr.fScript, slr.fLanguage);
00148   err = aBrowserShell->HandleUnicodeForKeyEvent(text, slr.fScript, slr.fLanguage, &eventRecord);
00149   // printf("err = %d\n", err);
00150   return err;
00151 }
00152 
00153 
00154 //*************************************************************************************
00155 //  HandleUpdateActiveInputArea
00156 //*************************************************************************************
00157 OSStatus CTextInputEventHandler::HandleUpdateActiveInputArea(
00158   CBrowserShell* aBrowserShell, 
00159   EventHandlerCallRef inHandlerCallRef, 
00160   EventRef inEvent)
00161 {
00162   NS_ENSURE_TRUE(aBrowserShell, eventNotHandledErr);
00163   PRUint32 fixLength;
00164   OSStatus err = ::GetEventParameter(inEvent, kEventParamTextInputSendFixLen, typeLongInteger, NULL, 
00165                           sizeof(fixLength), NULL, &fixLength);
00166   if (noErr != err)
00167     return eventParameterNotFoundErr;
00168 
00169   ScriptLanguageRecord slr;
00170   err = GetScriptLang(inEvent, slr);
00171   if (noErr != err)
00172     return eventParameterNotFoundErr;
00173   
00174   nsAutoString text;
00175   err = GetText(inEvent, text);
00176    if (noErr != err)
00177     return eventParameterNotFoundErr;
00178 
00179   // kEventParamTextInputSendHiliteRng is optional parameter, don't return if we cannot get it.
00180   
00181   TextRangeArray* hiliteRng = nsnull;                        
00182   UInt32 rngSize=0;   
00183   err = ::GetEventParameter(inEvent, kEventParamTextInputSendHiliteRng, typeTextRangeArray, NULL, 
00184                           0, NULL, &rngSize);
00185   if (noErr == err)  
00186   {
00187     TextRangeArray* pt = (TextRangeArray*)::malloc(rngSize);
00188     NS_WARN_IF_FALSE( (pt), "Cannot malloc for hiliteRng") ; 
00189     if (pt)
00190     { 
00191       hiliteRng = pt;
00192       err = ::GetEventParameter(inEvent, kEventParamTextInputSendHiliteRng, typeTextRangeArray, NULL, 
00193                               rngSize, &rngSize, hiliteRng);
00194       NS_WARN_IF_FALSE( (noErr == err), "Cannot get hiliteRng") ; 
00195     }                          
00196   }                     
00197   // printf("call HandleUpdateActiveInputArea textlength = %d ",text.Length());
00198   // printf("script=%d language=%d fixlen=%d\n", slr.fScript, slr.fLanguage, fixLength / 2);
00199   err = aBrowserShell->HandleUpdateActiveInputArea(text, slr.fScript, slr.fLanguage,
00200                                           fixLength / sizeof(PRUnichar), hiliteRng);
00201   if (hiliteRng)
00202      ::free(hiliteRng);
00203   return err;
00204 }
00205 //*************************************************************************************
00206 //  HandleUpdateActiveInputArea
00207 //*************************************************************************************
00208 OSStatus CTextInputEventHandler::HandleGetSelectedText(
00209   CBrowserShell* aBrowserShell, 
00210   EventHandlerCallRef inHandlerCallRef, 
00211   EventRef inEvent)
00212 {
00213   NS_ENSURE_TRUE(aBrowserShell, eventNotHandledErr);
00214 
00215   nsAutoString outString;
00216   OSStatus err = aBrowserShell->HandleGetSelectedText(outString);   
00217   if (noErr != err)
00218     return eventParameterNotFoundErr;
00219   
00220   err = ::SetEventParameter(inEvent, kEventParamTextInputReplyText, typeUnicodeText,
00221                           outString.Length()*sizeof(PRUnichar), outString.get());
00222   return err; 
00223 }
00224 
00225 
00226 //*************************************************************************************
00227 //  HandleOffsetToPos
00228 //*************************************************************************************
00229 OSStatus CTextInputEventHandler::HandleOffsetToPos(
00230   CBrowserShell* aBrowserShell, 
00231   EventHandlerCallRef inHandlerCallRef, 
00232   EventRef inEvent)
00233 {
00234   NS_ENSURE_TRUE(aBrowserShell, eventNotHandledErr);
00235   PRUint32 offset;
00236   OSStatus err = ::GetEventParameter(inEvent, kEventParamTextInputSendTextOffset, typeLongInteger, NULL, 
00237                           sizeof(offset), NULL, &offset);
00238   if (noErr != err)
00239     return eventParameterNotFoundErr;
00240 
00241   Point thePoint;
00242   // printf("call HandleOffsetToPos offset = %d\n", offset);
00243   err = aBrowserShell->HandleOffsetToPos(offset, &thePoint.h, &thePoint.v);   
00244   // printf("return %d, %d\n", thePoint.v, thePoint.h);                          
00245   if (noErr != err)
00246     return eventParameterNotFoundErr;
00247   
00248   err = ::SetEventParameter(inEvent, kEventParamTextInputReplyPoint, typeQDPoint,
00249                           sizeof(thePoint), &thePoint);
00250   return err; 
00251 }
00252 
00253 
00254 //*************************************************************************************
00255 //  HandlePosToOffset
00256 //*************************************************************************************
00257 OSStatus CTextInputEventHandler::HandlePosToOffset(
00258   CBrowserShell* aBrowserShell, 
00259   EventHandlerCallRef inHandlerCallRef, 
00260   EventRef inEvent)
00261 {
00262   NS_ENSURE_TRUE(aBrowserShell, eventNotHandledErr);
00263   PRInt32 offset;
00264   Point thePoint;
00265   short regionClass;
00266 
00267   OSStatus err = ::GetEventParameter(inEvent, kEventParamTextInputSendCurrentPoint, typeQDPoint, NULL, 
00268                                    sizeof(thePoint), NULL, &thePoint);
00269   if (noErr != err)
00270     return eventParameterNotFoundErr;
00271 
00272   // printf("call HandlePosToOffset Point = %d, %d\n", thePoint.h, thePoint.v);
00273   err = aBrowserShell->HandlePosToOffset(thePoint.h, thePoint.v, &offset, &regionClass);
00274   // printf("return offset = %d, region = %d\n", offset, regionClass);                          
00275   if (noErr != err)
00276     return eventParameterNotFoundErr;
00277 
00278   err = ::SetEventParameter(inEvent, kEventParamTextInputReplyRegionClass, typeShortInteger,
00279                           sizeof(regionClass), &regionClass);
00280   if (noErr != err)
00281     return eventParameterNotFoundErr;
00282   
00283   err = ::SetEventParameter(inEvent, kEventParamTextInputReplyTextOffset, typeLongInteger,
00284                           sizeof(offset), &offset);
00285   return err;   
00286 }
00287 
00288 
00289 //*************************************************************************************
00290 //  HandleAll
00291 //*************************************************************************************
00292 OSStatus CTextInputEventHandler::HandleAll(EventHandlerCallRef inHandlerCallRef, EventRef inEvent)
00293 {
00294   CBrowserShell* aBrowserShell = GetGeckoTarget();
00295   // if this is not an event for Gecko, just return eventNotHandledErr and let 
00296   // OS to fallback to class event handling 
00297   if (!aBrowserShell)
00298     return eventNotHandledErr;
00299   
00300   UInt32 eventClass = ::GetEventClass(inEvent);
00301   if (eventClass != kEventClassTextInput)
00302     return eventNotHandledErr;
00303 
00304   UInt32 eventKind = ::GetEventKind(inEvent);
00305   if ((kEventTextInputUpdateActiveInputArea != eventKind) &&
00306                   (kEventTextInputUnicodeForKeyEvent!= eventKind) &&
00307                   (kEventTextInputOffsetToPos != eventKind) &&
00308                   (kEventTextInputPosToOffset != eventKind) &&
00309                   (kEventTextInputGetSelectedText != eventKind))
00310     return eventNotHandledErr;
00311     
00312   switch(eventKind)
00313   {
00314     case kEventTextInputUpdateActiveInputArea:
00315       return HandleUpdateActiveInputArea(aBrowserShell, inHandlerCallRef, inEvent);
00316     case kEventTextInputUnicodeForKeyEvent:
00317       return HandleUnicodeForKeyEvent(aBrowserShell, inHandlerCallRef, inEvent);
00318     case kEventTextInputOffsetToPos:
00319       return HandleOffsetToPos(aBrowserShell, inHandlerCallRef, inEvent);
00320     case kEventTextInputPosToOffset:
00321       return HandlePosToOffset(aBrowserShell, inHandlerCallRef, inEvent);
00322     case kEventTextInputGetSelectedText:
00323       return HandleGetSelectedText(aBrowserShell, inHandlerCallRef, inEvent);
00324   }
00325   return eventNotHandledErr;
00326 }
00327 
00328 
00329 #pragma mark -
00330 
00331 //*************************************************************************************
00332 //  TextInputHandler
00333 //*************************************************************************************
00334 static pascal OSStatus TextInputHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
00335 {
00336    CTextInputEventHandler* realHandler = (CTextInputEventHandler*)inUserData;
00337    return realHandler->HandleAll(inHandlerCallRef, inEvent);
00338 }
00339 
00340 //*************************************************************************************
00341 //  InitializeTextInputEventHandling
00342 //*************************************************************************************
00343 void InitializeTextInputEventHandling()
00344 {
00345   static CTextInputEventHandler Singleton;
00346   EventTypeSpec eventTypes[5] = {
00347     {kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
00348     {kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
00349     {kEventClassTextInput, kEventTextInputOffsetToPos },
00350     {kEventClassTextInput, kEventTextInputPosToOffset },
00351     {kEventClassTextInput, kEventTextInputGetSelectedText }
00352   };  
00353   
00354   EventHandlerUPP textInputUPP = NewEventHandlerUPP(TextInputHandler); 
00355   OSStatus err = InstallApplicationEventHandler( textInputUPP, 5, eventTypes, &Singleton, NULL);
00356   NS_ASSERTION(err==noErr, "Cannot install carbon event");
00357 }