Back to index

lightning-sunbird  0.9+nobinonly
nsMacEventHandler.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Mark Mentovai <mark@moxienet.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsMacEventHandler.h"
00040 
00041 #include "nsWindow.h"
00042 #include "nsMacWindow.h"
00043 #include "nsCRT.h"
00044 #include "prinrval.h"
00045 
00046 #include <ToolUtils.h>
00047 #include <TextServices.h>
00048 #include <UnicodeConverter.h>
00049 
00050 #include "nsCarbonHelpers.h"
00051 #include "nsIRollupListener.h"
00052 #include "nsIMenuRollup.h"
00053 #include "nsGfxUtils.h"
00054 
00055 #include "nsIDocument.h"
00056 #include "nsIFrame.h"
00057 #include "nsIObjectFrame.h"
00058 #include "nsIPresShell.h"
00059 #include "nsIEventStateManager.h"
00060 #include "nsToolkit.h"
00061 
00062 static nsMacEventHandler* sLastActive;
00063 
00064 //#define DEBUG_TSM
00065 extern nsIRollupListener * gRollupListener;
00066 extern nsIWidget         * gRollupWidget;
00067 
00068 
00069 // from MacHeaders.c
00070 #ifndef topLeft
00071        #define topLeft(r)   (((Point *) &(r))[0])
00072 #endif
00073 #ifndef botRight
00074        #define botRight(r)  (((Point *) &(r))[1])
00075 #endif
00076 
00077 static void ConvertKeyEventToContextMenuEvent(const nsKeyEvent* inKeyEvent, nsMouseEvent* outCMEvent);
00078 static inline PRBool IsContextMenuKey(const nsKeyEvent& inKeyEvent);
00079 
00080 
00081 //-------------------------------------------------------------------------
00082 //
00083 //-------------------------------------------------------------------------
00084 nsMacEventDispatchHandler::nsMacEventDispatchHandler()
00085 {
00086        mActiveWidget = nsnull;
00087        mWidgetHit           = nsnull;
00088        mWidgetPointed       = nsnull;
00089 #if TRACK_MOUSE_LOC
00090   mLastGlobalMouseLoc.h = mLastGlobalMouseLoc.v = 0;
00091 #endif
00092 }
00093 
00094 
00095 //-------------------------------------------------------------------------
00096 //
00097 //-------------------------------------------------------------------------
00098 nsMacEventDispatchHandler::~nsMacEventDispatchHandler()
00099 {
00100        if (mActiveWidget)
00101        {
00102          mActiveWidget->RemoveDeleteObserver(this);
00103          mActiveWidget = nsnull;
00104        }
00105 
00106        if (mWidgetHit)
00107        {
00108          mWidgetHit->RemoveDeleteObserver(this);
00109          mWidgetHit = nsnull;
00110        }
00111 
00112        if (mWidgetPointed)
00113        {
00114          mWidgetPointed->RemoveDeleteObserver(this);
00115          mWidgetPointed = nsnull;
00116        }      
00117 }
00118 
00119 
00120 //-------------------------------------------------------------------------
00121 //
00122 //-------------------------------------------------------------------------
00123 void nsMacEventDispatchHandler::DispatchGuiEvent(nsWindow *aWidget, PRUint32 aEventType)
00124 {
00125        NS_ASSERTION(aWidget,"attempted to dispatch gui event to null widget");
00126        if (!aWidget)
00127               return;
00128 
00129        nsGUIEvent guiEvent(PR_TRUE, aEventType, aWidget);
00130        guiEvent.time = PR_IntervalNow();
00131        aWidget->DispatchWindowEvent(guiEvent);
00132 }
00133 
00134 //-------------------------------------------------------------------------
00135 //
00136 //-------------------------------------------------------------------------
00137 void nsMacEventDispatchHandler::DispatchSizeModeEvent(nsWindow *aWidget, nsSizeMode aMode)
00138 {
00139        NS_ASSERTION(aWidget,"attempted to dispatch gui event to null widget");
00140        if (!aWidget)
00141               return;
00142 
00143        nsSizeModeEvent event(PR_TRUE, NS_SIZEMODE, aWidget);
00144        event.time = PR_IntervalNow();
00145        event.mSizeMode = aMode;
00146        aWidget->DispatchWindowEvent(event);
00147 }
00148 
00149 //-------------------------------------------------------------------------
00150 //
00151 //-------------------------------------------------------------------------
00152 void nsMacEventDispatchHandler::SetFocus(nsWindow *aFocusedWidget)
00153 {
00154     // This short circut lives inside of nsEventStateManager now
00155        if (aFocusedWidget == mActiveWidget)
00156               return;
00157               
00158        // tell the old widget it is not focused
00159        if (mActiveWidget)
00160        {
00161               mActiveWidget->ResetInputState();
00162               mActiveWidget->RemoveDeleteObserver(this);
00163               //printf("nsMacEventDispatcher::SetFocus sends NS_LOSTFOCUS\n");
00164               DispatchGuiEvent(mActiveWidget, NS_LOSTFOCUS);
00165        }
00166 
00167        mActiveWidget = aFocusedWidget;
00168 
00169        // let the new one know it got the focus
00170        if (mActiveWidget)
00171        {
00172               mActiveWidget->AddDeleteObserver(this);
00173               //printf("nsMacEventDispatcher::SetFocus sends NS_GOTFOCUS\n");
00174               DispatchGuiEvent(mActiveWidget, NS_GOTFOCUS);
00175        }
00176 }
00177 
00178 //-------------------------------------------------------------------------
00179 //
00180 //-------------------------------------------------------------------------
00181 
00182 void nsMacEventDispatchHandler::SetActivated(nsWindow *aActivatedWidget)
00183 {
00184   //printf("nsMacEventDispatcher::SetActivated \n");
00185   
00186        if (aActivatedWidget == mActiveWidget) {
00187               //printf("already the active widget. Bailing!\n");
00188               return;
00189        }
00190 
00191   if(aActivatedWidget) {
00192     nsWindowType wtype;
00193     aActivatedWidget->GetWindowType(wtype);
00194     if ( eWindowType_popup == wtype ) {
00195       //printf("nsMacEventDispatcher::SetActivated type popup, bail\n");
00196       return;
00197     }
00198   }
00199   
00200        // tell the old widget it is not focused
00201        if (mActiveWidget)
00202        {
00203               mActiveWidget->ResetInputState();
00204               mActiveWidget->RemoveDeleteObserver(this);
00205               //printf("nsMacEventDispatchHandler::SetActivated sends NS_LOSTFOCUS\n");
00206               DispatchGuiEvent(mActiveWidget, NS_LOSTFOCUS);
00207        }
00208 
00209        mActiveWidget = aActivatedWidget;
00210 
00211        // let the new one know it got activation
00212        if (mActiveWidget)
00213        {
00214               mActiveWidget->AddDeleteObserver(this);
00215               //printf("nsMacEventDispatcher::SetActivated sends NS_GOTFOCUS\n");
00216               DispatchGuiEvent(mActiveWidget, NS_GOTFOCUS);
00217               
00218               //printf("nsMacEventDispatchHandler::SetActivated sends NS_ACTIVATE\n");
00219               DispatchGuiEvent(mActiveWidget, NS_ACTIVATE);
00220        }
00221 }
00222 
00223 //-------------------------------------------------------------------------
00224 //
00225 //-------------------------------------------------------------------------
00226 
00227 void nsMacEventDispatchHandler::SetDeactivated(nsWindow *aDeactivatedWidget)
00228 {
00229     //printf("nsMacEventDispatchHandler::SetDeactivated\n");
00230     if(aDeactivatedWidget) {
00231       nsWindowType wtype;
00232       aDeactivatedWidget->GetWindowType(wtype);
00233       if ( eWindowType_popup == wtype ) {
00234         //printf("nsMacEventDispatchHandler::SetDeactivated type popup, bail\n");
00235         return;
00236       }
00237     }
00238       
00239     // If the deactivated toplevel window contains mActiveWidget, then
00240     // clear out mActiveWidget.
00241 
00242     if (mActiveWidget) {
00243       nsCOMPtr<nsIWidget> curWin = do_QueryInterface(NS_STATIC_CAST(nsIWidget*, mActiveWidget));
00244       for (;;) {
00245         nsCOMPtr<nsIWidget> parent = dont_AddRef(curWin->GetParent());
00246         if (!parent)
00247           break;
00248         curWin = parent;
00249       }
00250 
00251       if (NS_STATIC_CAST(nsWindow*, NS_STATIC_CAST(nsIWidget*, curWin)) == aDeactivatedWidget) {
00252         //printf("   nsMacEventDispatchHandler::SetDeactivated sends NS_DEACTIVATE\n");
00253         mActiveWidget->RemoveDeleteObserver(this);
00254         mActiveWidget = nsnull;
00255       }
00256     }
00257 
00258     DispatchGuiEvent(aDeactivatedWidget, NS_DEACTIVATE);       
00259 }
00260 
00261 //-------------------------------------------------------------------------
00262 //
00263 //-------------------------------------------------------------------------
00264 void nsMacEventDispatchHandler::SetWidgetHit(nsWindow *aWidgetHit)
00265 {
00266        if (aWidgetHit == mWidgetHit)
00267               return;
00268 
00269        if (mWidgetHit)
00270          if (! mWidgetHit->RemoveDeleteObserver(this))
00271               NS_WARNING("nsMacFocusHandler wasn't in the WidgetHit observer list");
00272 
00273        mWidgetHit = aWidgetHit;
00274 
00275        if (mWidgetHit)
00276          mWidgetHit->AddDeleteObserver(this);
00277 }
00278 
00279 
00280 //-------------------------------------------------------------------------
00281 //
00282 //-------------------------------------------------------------------------
00283 void nsMacEventDispatchHandler::SetWidgetPointed(nsWindow *aWidgetPointed)
00284 {
00285        if (aWidgetPointed == mWidgetPointed) {
00286               return;
00287     }
00288        
00289        if (mWidgetPointed) 
00290          if (! mWidgetPointed->RemoveDeleteObserver(this)) 
00291               NS_WARNING("nsMacFocusHandler wasn't in the WidgetPointed observer list");
00292     
00293        mWidgetPointed = aWidgetPointed;
00294     
00295        if (mWidgetPointed)
00296          mWidgetPointed->AddDeleteObserver(this);
00297 }
00298 
00299 
00300 //-------------------------------------------------------------------------
00301 //
00302 //-------------------------------------------------------------------------
00303 void nsMacEventDispatchHandler::NotifyDelete(void* aDeletedObject)
00304 {
00305        if (mActiveWidget == aDeletedObject)
00306               mActiveWidget = nsnull;
00307        
00308        if (mWidgetHit == aDeletedObject)
00309               mWidgetHit = nsnull;
00310 
00311        if (mWidgetPointed == aDeletedObject)
00312               mWidgetPointed = nsnull;
00313 
00314 }
00315 
00316 
00317 #if TRACK_MOUSE_LOC
00318 
00319 void nsMacEventDispatchHandler::SetGlobalPoint(Point inPoint)
00320 {
00321   mLastGlobalMouseLoc = inPoint;
00322 }
00323 
00324 #endif
00325 
00326 
00327 #pragma mark -
00328 
00329 //-------------------------------------------------------------------------
00330 //
00331 // nsMacEventHandler constructor/destructor
00332 //
00333 //-------------------------------------------------------------------------
00334 nsMacEventHandler::nsMacEventHandler(nsMacWindow* aTopLevelWidget,
00335                                      nsMacEventDispatchHandler* aEventDispatchHandler)
00336 {
00337   OSErr err;
00338   InterfaceTypeList supportedServices;
00339 
00340   mTopLevelWidget = aTopLevelWidget;
00341 
00342   //
00343   // create a TSMDocument for this window.  We are allocating a TSM document for
00344   // each Mac window
00345   //
00346   mTSMDocument = nsnull;
00347   supportedServices[0] = kUnicodeDocument;
00348   err = ::NewTSMDocument(1, supportedServices,&mTSMDocument, (long)this);
00349   NS_ASSERTION(err==noErr, "nsMacEventHandler::nsMacEventHandler: NewTSMDocument failed.");
00350 #ifdef DEBUG_TSM
00351   printf("nsMacEventHandler::nsMacEventHandler: created TSMDocument[%p]\n", mTSMDocument);
00352 #endif
00353 
00354   // make sure we do not use input widnow even some other code turn it for default by calling 
00355   // ::UseInputWindow(nsnull, TRUE); 
00356   if (mTSMDocument)
00357     ::UseInputWindow(mTSMDocument, FALSE); 
00358          
00359   mIMEIsComposing = PR_FALSE;
00360   mIMECompositionStr = nsnull;
00361 
00362   mKeyIgnore = PR_FALSE;
00363   mKeyHandled = PR_FALSE;
00364 
00365   mLastModifierState = 0;
00366 
00367   mMouseInWidgetHit = PR_FALSE;
00368 
00369   ClearLastMouseUp();
00370 
00371   if (aEventDispatchHandler) {
00372     mEventDispatchHandler = aEventDispatchHandler;
00373     mOwnEventDispatchHandler = PR_FALSE;
00374   }
00375   else {
00376     mEventDispatchHandler = new nsMacEventDispatchHandler();
00377     mOwnEventDispatchHandler = PR_TRUE;
00378   }
00379 }
00380 
00381 
00382 nsMacEventHandler::~nsMacEventHandler()
00383 {
00384        if (mTSMDocument)
00385               (void)::DeleteTSMDocument(mTSMDocument);
00386        if(nsnull != mIMECompositionStr) {
00387               delete mIMECompositionStr;
00388               mIMECompositionStr = nsnull;
00389        }
00390 
00391        if (mOwnEventDispatchHandler)
00392               delete mEventDispatchHandler;
00393 
00394   if (sLastActive == this) {
00395     // This shouldn't happen
00396     sLastActive = nsnull;
00397   }
00398 }
00399 
00400 
00401 
00402 #pragma mark -
00403 //-------------------------------------------------------------------------
00404 //
00405 // HandleOSEvent
00406 //
00407 //-------------------------------------------------------------------------
00408 PRBool nsMacEventHandler::HandleOSEvent ( EventRecord& aOSEvent )
00409 {
00410        PRBool retVal = PR_FALSE;
00411 
00412        switch (aOSEvent.what)
00413        {
00414               case mouseDown:
00415                      retVal = HandleMouseDownEvent(aOSEvent);
00416                      break;
00417 
00418               case mouseUp:
00419                      retVal = HandleMouseUpEvent(aOSEvent);
00420                      break;
00421 
00422               case osEvt:
00423               {
00424                      unsigned char eventType = ((aOSEvent.message >> 24) & 0x00ff);
00425                      if (eventType == mouseMovedMessage)
00426                      {
00427                             retVal = HandleMouseMoveEvent(aOSEvent);
00428                      }
00429               }
00430               break;
00431        }
00432 
00433        return retVal;
00434 }
00435 
00436 
00437 #if USE_MENUSELECT
00438 
00439 //-------------------------------------------------------------------------
00440 //
00441 // Handle Menu commands
00442 //
00443 //-------------------------------------------------------------------------
00444 PRBool nsMacEventHandler::HandleMenuCommand(
00445   EventRecord& aOSEvent,
00446   long         aMenuResult)
00447 {
00448        // get the focused widget
00449        nsWindow* focusedWidget = mEventDispatchHandler->GetActive();
00450        if (!focusedWidget)
00451               focusedWidget = mTopLevelWidget;
00452 
00453        // nsEvent
00454        nsMenuEvent menuEvent(PR_TRUE, NS_MENU_SELECTED, focusedWidget);
00455        menuEvent.point.x           = aOSEvent.where.h;
00456        menuEvent.point.y           = aOSEvent.where.v;
00457        menuEvent.time                     = PR_IntervalNow();
00458 
00459        // nsGUIEvent
00460        menuEvent.nativeMsg  = (void*)&aOSEvent;
00461 
00462        // nsMenuEvent
00463   // TODO: initialize mMenuItem
00464        menuEvent.mCommand   = aMenuResult;
00465 
00466        // dispatch the menu event
00467        PRBool eventHandled = focusedWidget->DispatchWindowEvent(menuEvent);
00468        
00469        // if the menu event is not processed by the focused widget, propagate it
00470        // through the different parents all the way up to the top-level window
00471        if (! eventHandled)
00472        {
00473               // make sure the focusedWidget wasn't changed or deleted
00474               // when we dispatched the event (even though if we get here, 
00475               // the event is supposed to not have been handled)
00476               if (focusedWidget == mEventDispatchHandler->GetActive())
00477               {
00478                      nsCOMPtr<nsIWidget> grandParent;
00479                      nsCOMPtr<nsIWidget> parent ( dont_AddRef(focusedWidget->GetParent()) );
00480                      while (parent)
00481                      {
00482                             menuEvent.widget = parent;
00483                             eventHandled = (static_cast<nsWindow*>(static_cast<nsIWidget*>(parent)))->DispatchWindowEvent(menuEvent);
00484                             if (eventHandled)
00485                             {
00486                                    break;
00487                             }
00488                             else
00489                             {
00490                                    grandParent = dont_AddRef(parent->GetParent());
00491                                    parent = grandParent;
00492                             }
00493                      }
00494               }
00495        }
00496 
00497        return eventHandled;
00498 }
00499 
00500 #endif
00501 
00502 
00503 void
00504 nsMacEventHandler::InitializeMouseEvent(nsMouseEvent& aMouseEvent,
00505                                         nsPoint&      aPoint,
00506                                         PRInt16       aModifiers,
00507                                         PRUint32      aClickCount)
00508 {
00509   // nsEvent
00510   aMouseEvent.point      = aPoint;
00511   aMouseEvent.time       = PR_IntervalNow();
00512 
00513   // nsInputEvent
00514   aMouseEvent.isShift    = ((aModifiers & shiftKey)   != 0);
00515   aMouseEvent.isControl  = ((aModifiers & controlKey) != 0);
00516   aMouseEvent.isAlt      = ((aModifiers & optionKey)  != 0);
00517   aMouseEvent.isMeta     = ((aModifiers & cmdKey)     != 0);
00518 
00519   // nsMouseEvent
00520   aMouseEvent.clickCount = aClickCount;
00521 }
00522 
00523 
00524 //-------------------------------------------------------------------------
00525 //
00526 // DragEvent
00527 //
00528 //-------------------------------------------------------------------------
00529 //
00530 // Someone on the outside told us that something related to a drag is
00531 // happening.  The exact event type is passed in as |aMessage|. We need to
00532 // send this event into Gecko for processing.  Create a Gecko event (using
00533 // the appropriate message type) and pass it along.
00534 //
00535 PRBool nsMacEventHandler::DragEvent(unsigned int aMessage,
00536                                     Point        aMouseGlobal,
00537                                     UInt16       aKeyModifiers)
00538 {
00539   // Convert the mouse to local coordinates.  We have to do all the funny port
00540   // origin stuff just in case it has been changed.
00541   Point hitPointLocal = aMouseGlobal;
00542   WindowRef wind =
00543    NS_STATIC_CAST(WindowRef, mTopLevelWidget->GetNativeData(NS_NATIVE_DISPLAY));
00544   nsGraphicsUtils::SafeSetPortWindowPort(wind);
00545   {
00546     StOriginSetter  originSetter(wind);
00547     ::GlobalToLocal(&hitPointLocal);
00548   }
00549   nsPoint widgetHitPoint(hitPointLocal.h, hitPointLocal.v);
00550 
00551   nsWindow* widgetHit = mTopLevelWidget->FindWidgetHit(hitPointLocal);
00552   if (widgetHit) {
00553     // Adjust from local coordinates to window coordinates in case the hit
00554     // widget isn't at (0, 0).
00555     nsRect bounds;
00556     widgetHit->GetBounds(bounds);
00557     nsPoint widgetOrigin(bounds.x, bounds.y);
00558     widgetHit->LocalToWindowCoordinate(widgetOrigin);
00559     widgetHitPoint.MoveBy(-widgetOrigin.x, -widgetOrigin.y);          
00560   }
00561 
00562   // Note that aMessage will be NS_DRAGDROP_(ENTER|EXIT|OVER|DROP) depending
00563   // on the state of the drag relative to the top-level window, not the
00564   // widget that interests us.  As a result, NS_DRAGDROP_ENTER and
00565   // NS_DRAGDROP_EXIT events must be synthesized as the drag moves between
00566   // widgets in this window.
00567 
00568   if (aMessage == NS_DRAGDROP_EXIT) {
00569     // If the drag is leaving the window, it can't be over a widget contained
00570     // within the window.
00571     widgetHit = nsnull;
00572   }
00573 
00574   nsWindow* lastWidget = mEventDispatchHandler->GetWidgetPointed();
00575   if (lastWidget != widgetHit) {
00576     if (aMessage != NS_DRAGDROP_ENTER) {
00577       if (lastWidget) {
00578         // Send an NS_DRAGDROP_EXIT event to the last widget.  This is not done
00579         // if aMessage == NS_DRAGDROP_ENTER, because that indicates that the
00580         // drag is either beginning (in which case there is no valid last
00581         // widget for the drag) or reentering the window (in which case
00582         // NS_DRAGDROP_EXIT was sent when the mouse left the window).
00583 
00584         nsMouseEvent exitEvent(PR_TRUE, NS_DRAGDROP_EXIT, lastWidget,
00585                                nsMouseEvent::eReal);
00586         nsPoint zero(0, 0);
00587         InitializeMouseEvent(exitEvent, zero, aKeyModifiers, 1);
00588         lastWidget->DispatchMouseEvent(exitEvent);
00589       }
00590 
00591       if (aMessage != NS_DRAGDROP_EXIT && widgetHit) {
00592         // Send an NS_DRAGDROP_ENTER event to the new widget.  This is not
00593         // done when aMessage == NS_DRAGDROP_EXIT, because that indicates
00594         // that the drag is leaving the window.
00595 
00596         nsMouseEvent enterEvent(PR_TRUE, NS_DRAGDROP_ENTER, widgetHit,
00597                                 nsMouseEvent::eReal);
00598         InitializeMouseEvent(enterEvent, widgetHitPoint, aKeyModifiers, 1);
00599         widgetHit->DispatchMouseEvent(enterEvent);
00600       }
00601     }
00602   }
00603 
00604   // update the tracking of which widget the mouse is now over.
00605   mEventDispatchHandler->SetWidgetPointed(widgetHit);
00606 
00607   if (!widgetHit) {
00608     // There is no widget to receive the event.  This happens when the drag
00609     // leaves the window or when the drag moves over a part of the window
00610     // not containing any widget, such as the title bar.  When appropriate,
00611     // NS_DRAGDROP_EXIT was dispatched to lastWidget above, so there's nothing
00612     // to do but return.
00613     return PR_TRUE;
00614   }
00615 
00616   nsMouseEvent geckoEvent(PR_TRUE, aMessage, widgetHit, nsMouseEvent::eReal);
00617   InitializeMouseEvent(geckoEvent, widgetHitPoint, aKeyModifiers, 1);
00618   widgetHit->DispatchMouseEvent(geckoEvent);
00619 
00620   return PR_TRUE;
00621 }
00622 
00623 
00624 #pragma mark -
00625 
00626 //-------------------------------------------------------------------------
00627 //
00628 // ConvertMacToRaptorKeyCode
00629 //
00630 //-------------------------------------------------------------------------
00631 
00632 
00633 // Key code constants
00634 enum
00635 {
00636        kEscapeKeyCode                     = 0x35,
00637        kCommandKeyCode     = 0x37,
00638        kShiftKeyCode                      = 0x38,
00639        kCapsLockKeyCode            = 0x39,
00640        kControlKeyCode                    = 0x3B,
00641        kOptionkeyCode                     = 0x3A,              // left and right option keys
00642        kClearKeyCode                      = 0x47,
00643        
00644        // function keys
00645        kF1KeyCode                                = 0x7A,
00646        kF2KeyCode                                = 0x78,
00647        kF3KeyCode                                = 0x63,
00648        kF4KeyCode                                = 0x76,
00649        kF5KeyCode                                = 0x60,
00650        kF6KeyCode                                = 0x61,
00651        kF7KeyCode                                = 0x62,
00652        kF8KeyCode                                = 0x64,
00653        kF9KeyCode                                = 0x65,
00654        kF10KeyCode                               = 0x6D,
00655        kF11KeyCode                               = 0x67,
00656        kF12KeyCode                               = 0x6F,
00657        kF13KeyCode                               = 0x69,
00658        kF14KeyCode                               = 0x6B,
00659        kF15KeyCode                               = 0x71,
00660        
00661        kPrintScreenKeyCode  = kF13KeyCode,
00662        kScrollLockKeyCode   = kF14KeyCode,
00663        kPauseKeyCode                      = kF15KeyCode,
00664        
00665        // keypad
00666        kKeypad0KeyCode                    = 0x52,
00667        kKeypad1KeyCode                    = 0x53,
00668        kKeypad2KeyCode                    = 0x54,
00669        kKeypad3KeyCode                    = 0x55,
00670        kKeypad4KeyCode                    = 0x56,
00671        kKeypad5KeyCode                    = 0x57,
00672        kKeypad6KeyCode                    = 0x58,
00673        kKeypad7KeyCode                    = 0x59,
00674        kKeypad8KeyCode                    = 0x5B,
00675        kKeypad9KeyCode                    = 0x5C,
00676        
00677        kKeypadMultiplyKeyCode      = 0x43,
00678        kKeypadAddKeyCode                         = 0x45,
00679        kKeypadSubtractKeyCode      = 0x4E,
00680        kKeypadDecimalKeyCode              = 0x41,
00681        kKeypadDivideKeyCode        = 0x4B,
00682        kKeypadEqualsKeyCode        = 0x51,                     // no correpsonding raptor key code
00683        kEnterKeyCode           = 0x4C,
00684        kReturnKeyCode          = 0x24,
00685        kPowerbookEnterKeyCode  = 0x34,     // Enter on Powerbook's keyboard is different
00686        
00687        kHelpKeyCode                                     = 0x72,                            // also insert key
00688        kDeleteKeyCode                                   = 0x75,                            // also forward delete key
00689        kTabKeyCode                                             = 0x30,
00690        kBackspaceKeyCode       = 0x33,
00691        kHomeKeyCode                                     = 0x73,       
00692        kEndKeyCode                                             = 0x77,
00693        kPageUpKeyCode                                   = 0x74,
00694        kPageDownKeyCode                          = 0x79,
00695        kLeftArrowKeyCode                         = 0x7B,
00696        kRightArrowKeyCode                 = 0x7C,
00697        kUpArrowKeyCode                                  = 0x7E,
00698        kDownArrowKeyCode                         = 0x7D
00699        
00700 };
00701 
00702 static PRUint32 ConvertMacToRaptorKeyCode(char charCode, UInt32 keyCode, UInt32 eventModifiers)
00703 {
00704        PRUint32      raptorKeyCode = 0;
00705        
00706        switch (keyCode)
00707        {
00708 //  case ??            :       raptorKeyCode = nsIDOMKeyEvent::DOM_VK_CANCEL;    break;     // don't know what this key means. Nor does joki
00709 
00710 // modifiers. We don't get separate events for these
00711     case kShiftKeyCode:         raptorKeyCode = nsIDOMKeyEvent::DOM_VK_SHIFT;         break;
00712     case kCommandKeyCode:       raptorKeyCode = nsIDOMKeyEvent::DOM_VK_META;          break;
00713     case kCapsLockKeyCode:      raptorKeyCode = nsIDOMKeyEvent::DOM_VK_CAPS_LOCK;     break;
00714     case kControlKeyCode:       raptorKeyCode = nsIDOMKeyEvent::DOM_VK_CONTROL;       break;
00715     case kOptionkeyCode:        raptorKeyCode = nsIDOMKeyEvent::DOM_VK_ALT;           break;
00716 
00717 // function keys
00718     case kF1KeyCode:            raptorKeyCode = nsIDOMKeyEvent::DOM_VK_F1;            break;
00719     case kF2KeyCode:            raptorKeyCode = nsIDOMKeyEvent::DOM_VK_F2;            break;
00720     case kF3KeyCode:            raptorKeyCode = nsIDOMKeyEvent::DOM_VK_F3;            break;
00721     case kF4KeyCode:            raptorKeyCode = nsIDOMKeyEvent::DOM_VK_F4;            break;
00722     case kF5KeyCode:            raptorKeyCode = nsIDOMKeyEvent::DOM_VK_F5;            break;
00723     case kF6KeyCode:            raptorKeyCode = nsIDOMKeyEvent::DOM_VK_F6;            break;
00724     case kF7KeyCode:            raptorKeyCode = nsIDOMKeyEvent::DOM_VK_F7;            break;
00725     case kF8KeyCode:            raptorKeyCode = nsIDOMKeyEvent::DOM_VK_F8;            break;
00726     case kF9KeyCode:            raptorKeyCode = nsIDOMKeyEvent::DOM_VK_F9;            break;
00727     case kF10KeyCode:           raptorKeyCode = nsIDOMKeyEvent::DOM_VK_F10;           break;
00728     case kF11KeyCode:           raptorKeyCode = nsIDOMKeyEvent::DOM_VK_F11;           break;
00729     case kF12KeyCode:           raptorKeyCode = nsIDOMKeyEvent::DOM_VK_F12;           break;
00730 //  case kF13KeyCode:           raptorKeyCode = nsIDOMKeyEvent::DOM_VK_F13;           break;    // clash with the 3 below
00731 //  case kF14KeyCode:           raptorKeyCode = nsIDOMKeyEvent::DOM_VK_F14;           break;
00732 //  case kF15KeyCode:           raptorKeyCode = nsIDOMKeyEvent::DOM_VK_F15;           break;
00733     case kPauseKeyCode:         raptorKeyCode = nsIDOMKeyEvent::DOM_VK_PAUSE;         break;
00734     case kScrollLockKeyCode:    raptorKeyCode = nsIDOMKeyEvent::DOM_VK_SCROLL_LOCK;   break;
00735     case kPrintScreenKeyCode:   raptorKeyCode = nsIDOMKeyEvent::DOM_VK_PRINTSCREEN;   break;
00736 
00737 // keypad
00738     case kKeypad0KeyCode:        raptorKeyCode = nsIDOMKeyEvent::DOM_VK_NUMPAD0;      break;
00739     case kKeypad1KeyCode:        raptorKeyCode = nsIDOMKeyEvent::DOM_VK_NUMPAD1;      break;
00740     case kKeypad2KeyCode:        raptorKeyCode = nsIDOMKeyEvent::DOM_VK_NUMPAD2;      break;
00741     case kKeypad3KeyCode:        raptorKeyCode = nsIDOMKeyEvent::DOM_VK_NUMPAD3;      break;
00742     case kKeypad4KeyCode:        raptorKeyCode = nsIDOMKeyEvent::DOM_VK_NUMPAD4;      break;
00743     case kKeypad5KeyCode:        raptorKeyCode = nsIDOMKeyEvent::DOM_VK_NUMPAD5;      break;
00744     case kKeypad6KeyCode:        raptorKeyCode = nsIDOMKeyEvent::DOM_VK_NUMPAD6;      break;
00745     case kKeypad7KeyCode:        raptorKeyCode = nsIDOMKeyEvent::DOM_VK_NUMPAD7;      break;
00746     case kKeypad8KeyCode:        raptorKeyCode = nsIDOMKeyEvent::DOM_VK_NUMPAD8;      break;
00747     case kKeypad9KeyCode:        raptorKeyCode = nsIDOMKeyEvent::DOM_VK_NUMPAD9;      break;
00748 
00749     case kKeypadMultiplyKeyCode: raptorKeyCode = nsIDOMKeyEvent::DOM_VK_MULTIPLY;     break;
00750     case kKeypadAddKeyCode:      raptorKeyCode = nsIDOMKeyEvent::DOM_VK_ADD;          break;
00751     case kKeypadSubtractKeyCode: raptorKeyCode = nsIDOMKeyEvent::DOM_VK_SUBTRACT;     break;
00752     case kKeypadDecimalKeyCode:  raptorKeyCode = nsIDOMKeyEvent::DOM_VK_DECIMAL;      break;
00753     case kKeypadDivideKeyCode:   raptorKeyCode = nsIDOMKeyEvent::DOM_VK_DIVIDE;       break;
00754 //  case ??             :        raptorKeyCode = nsIDOMKeyEvent::DOM_VK_SEPARATOR;    break;
00755 
00756 // this may clash with vk_insert, but help key is more useful in mozilla
00757     case kHelpKeyCode:          raptorKeyCode = nsIDOMKeyEvent::DOM_VK_HELP;          break;
00758     case kDeleteKeyCode:        raptorKeyCode = nsIDOMKeyEvent::DOM_VK_DELETE;        break;
00759     case kEscapeKeyCode:        raptorKeyCode = nsIDOMKeyEvent::DOM_VK_ESCAPE;        break;
00760     case kClearKeyCode:         raptorKeyCode = nsIDOMKeyEvent::DOM_VK_CLEAR;         break;
00761 
00762     case kBackspaceKeyCode:     raptorKeyCode = nsIDOMKeyEvent::DOM_VK_BACK_SPACE;    break;
00763     case kTabKeyCode:           raptorKeyCode = nsIDOMKeyEvent::DOM_VK_TAB;           break;
00764     case kHomeKeyCode:          raptorKeyCode = nsIDOMKeyEvent::DOM_VK_HOME;          break;
00765     case kEndKeyCode:           raptorKeyCode = nsIDOMKeyEvent::DOM_VK_END;           break;
00766     case kPageUpKeyCode:        raptorKeyCode = nsIDOMKeyEvent::DOM_VK_PAGE_UP;       break;
00767     case kPageDownKeyCode:      raptorKeyCode = nsIDOMKeyEvent::DOM_VK_PAGE_DOWN;     break;
00768     case kLeftArrowKeyCode:     raptorKeyCode = nsIDOMKeyEvent::DOM_VK_LEFT;          break;
00769     case kRightArrowKeyCode:    raptorKeyCode = nsIDOMKeyEvent::DOM_VK_RIGHT;         break;
00770     case kUpArrowKeyCode:       raptorKeyCode = nsIDOMKeyEvent::DOM_VK_UP;            break;
00771     case kDownArrowKeyCode:     raptorKeyCode = nsIDOMKeyEvent::DOM_VK_DOWN;          break;
00772 
00773               default:
00774                             if ((eventModifiers & controlKey) != 0)
00775                               charCode += 64;
00776               
00777                             // if we haven't gotten the key code already, look at the char code
00778                             switch (charCode)
00779                             {
00780           case kReturnCharCode: raptorKeyCode = nsIDOMKeyEvent::DOM_VK_RETURN;       break;
00781           case kEnterCharCode:  raptorKeyCode = nsIDOMKeyEvent::DOM_VK_RETURN;       break;    // fix me!
00782           case ' ':             raptorKeyCode = nsIDOMKeyEvent::DOM_VK_SPACE;        break;
00783           case ';':             raptorKeyCode = nsIDOMKeyEvent::DOM_VK_SEMICOLON;    break;
00784           case '=':             raptorKeyCode = nsIDOMKeyEvent::DOM_VK_EQUALS;       break;
00785           case ',':             raptorKeyCode = nsIDOMKeyEvent::DOM_VK_COMMA;        break;
00786           case '.':             raptorKeyCode = nsIDOMKeyEvent::DOM_VK_PERIOD;       break;
00787           case '/':             raptorKeyCode = nsIDOMKeyEvent::DOM_VK_SLASH;        break;
00788           case '`':             raptorKeyCode = nsIDOMKeyEvent::DOM_VK_BACK_QUOTE;   break;
00789           case '{':
00790           case '[':             raptorKeyCode = nsIDOMKeyEvent::DOM_VK_OPEN_BRACKET; break;
00791           case '\\':            raptorKeyCode = nsIDOMKeyEvent::DOM_VK_BACK_SLASH;   break;
00792           case '}':
00793           case ']':             raptorKeyCode = nsIDOMKeyEvent::DOM_VK_CLOSE_BRACKET; break;
00794           case '\'':
00795           case '"':             raptorKeyCode = nsIDOMKeyEvent::DOM_VK_QUOTE;        break;
00796 
00797                                    default:
00798                                           
00799                                           if (charCode >= '0' && charCode <= '9')          // numerals
00800                                           {
00801                                                  raptorKeyCode = charCode;
00802                                           }
00803                                           else if (charCode >= 'a' && charCode <= 'z')            // lowercase
00804                                           {
00805                                                  raptorKeyCode = toupper(charCode);
00806                                           }
00807                                           else if (charCode >= 'A' && charCode <= 'Z')            // uppercase
00808                                           {
00809                                                  raptorKeyCode = charCode;
00810                                           }
00811 
00812                                           break;
00813                             }
00814        }
00815 
00816        return raptorKeyCode;
00817 }
00818 
00819 
00820 //-------------------------------------------------------------------------
00821 //
00822 // InitializeKeyEvent
00823 //
00824 //-------------------------------------------------------------------------
00825 
00826 void nsMacEventHandler::InitializeKeyEvent(nsKeyEvent& aKeyEvent, 
00827     EventRecord& aOSEvent, nsWindow* aFocusedWidget, PRUint32 aMessage,
00828     PRBool aConvertChar)
00829 {
00830        //
00831        // initalize the basic message parts
00832        //
00833        aKeyEvent.time                            = PR_IntervalNow();
00834        
00835        //
00836        // initalize the GUI event parts
00837        //
00838   aKeyEvent.widget = aFocusedWidget;
00839        aKeyEvent.nativeMsg         = (void*)&aOSEvent;
00840        
00841        //
00842        // nsInputEvent parts
00843        //
00844        aKeyEvent.isShift                  = ((aOSEvent.modifiers & shiftKey) != 0);
00845        aKeyEvent.isControl         = ((aOSEvent.modifiers & controlKey) != 0);
00846        aKeyEvent.isAlt                           = ((aOSEvent.modifiers & optionKey) != 0);
00847        aKeyEvent.isMeta            = ((aOSEvent.modifiers & cmdKey) != 0);
00848        
00849        //
00850        // nsKeyEvent parts
00851        //
00852   if (aMessage == NS_KEY_PRESS 
00853               && !IsSpecialRaptorKey((aOSEvent.message & keyCodeMask) >> 8) )
00854        {
00855     if (aKeyEvent.isControl)
00856               {
00857       if (aConvertChar) 
00858       {
00859                      aKeyEvent.charCode = (aOSEvent.message & charCodeMask);
00860         if (aKeyEvent.charCode <= 26)
00861                      {
00862           if (aKeyEvent.isShift)
00863                                    aKeyEvent.charCode += 'A' - 1;
00864                             else
00865                                    aKeyEvent.charCode += 'a' - 1;
00866         } // if (aKeyEvent.charCode <= 26)
00867       }
00868                      aKeyEvent.keyCode    = 0;
00869     } // if (aKeyEvent.isControl)
00870     else // else for if (aKeyEvent.isControl)
00871               {
00872       if (!aKeyEvent.isMeta)
00873                      {
00874                             aKeyEvent.isControl = aKeyEvent.isAlt = aKeyEvent.isMeta = 0;
00875       } // if (!aKeyEvent.isMeta)
00876     
00877                      aKeyEvent.keyCode    = 0;
00878       if (aConvertChar) 
00879       {
00880                      aKeyEvent.charCode = ConvertKeyEventToUnicode(aOSEvent);
00881         if (aKeyEvent.isShift && aKeyEvent.charCode <= 'z' && aKeyEvent.charCode >= 'a') 
00882         {
00883                        aKeyEvent.charCode -= 32;
00884                      }
00885                      NS_ASSERTION(0 != aKeyEvent.charCode, "nsMacEventHandler::InitializeKeyEvent: ConvertKeyEventToUnicode returned 0.");
00886       }
00887     } // else for if (aKeyEvent.isControl)
00888        } // if (message == NS_KEY_PRESS && !IsSpecialRaptorKey((aOSEvent.message & keyCodeMask) >> 8) )
00889        else
00890        {
00891               aKeyEvent.keyCode = ConvertMacToRaptorKeyCode(aOSEvent.message & charCodeMask, (aOSEvent.message & keyCodeMask) >> 8, aOSEvent.modifiers);
00892               aKeyEvent.charCode = 0;
00893        } // else for  if (message == NS_KEY_PRESS && !IsSpecialRaptorKey((aOSEvent.message & keyCodeMask) >> 8) )
00894   
00895   //
00896   // obscure cursor if appropriate
00897   //
00898   if (aMessage == NS_KEY_PRESS 
00899               && !aKeyEvent.isMeta 
00900               && aKeyEvent.keyCode != nsIDOMKeyEvent::DOM_VK_PAGE_UP 
00901               && aKeyEvent.keyCode != nsIDOMKeyEvent::DOM_VK_PAGE_DOWN
00902               // also consider:  function keys and sole modifier keys
00903        ) 
00904        {
00905     ::ObscureCursor();
00906   }
00907 }
00908 
00909 
00910 
00911 //-------------------------------------------------------------------------
00912 //
00913 // IsSpecialRaptorKey
00914 //
00915 //-------------------------------------------------------------------------
00916 
00917 PRBool nsMacEventHandler::IsSpecialRaptorKey(UInt32 macKeyCode)
00918 {
00919        PRBool isSpecial;
00920 
00921        // 
00922        // this table is used to determine which keys are special and should not generate a charCode
00923        //     
00924        switch (macKeyCode)
00925        {
00926 // modifiers. We don't get separate events for these
00927 // yet
00928               case kEscapeKeyCode:                      isSpecial = PR_TRUE; break;
00929               case kShiftKeyCode:                              isSpecial = PR_TRUE; break;
00930               case kCommandKeyCode:       isSpecial = PR_TRUE; break;
00931               case kCapsLockKeyCode:                    isSpecial = PR_TRUE; break;
00932               case kControlKeyCode:                            isSpecial = PR_TRUE; break;
00933               case kOptionkeyCode:                      isSpecial = PR_TRUE; break;
00934               case kClearKeyCode:                              isSpecial = PR_TRUE; break;
00935 
00936 // function keys
00937               case kF1KeyCode:                                 isSpecial = PR_TRUE; break;
00938               case kF2KeyCode:                                 isSpecial = PR_TRUE; break;
00939               case kF3KeyCode:                                 isSpecial = PR_TRUE; break;
00940               case kF4KeyCode:                                 isSpecial = PR_TRUE; break;
00941               case kF5KeyCode:                                 isSpecial = PR_TRUE; break;
00942               case kF6KeyCode:                                 isSpecial = PR_TRUE; break;
00943               case kF7KeyCode:                                 isSpecial = PR_TRUE; break;
00944               case kF8KeyCode:                                 isSpecial = PR_TRUE; break;
00945               case kF9KeyCode:                                 isSpecial = PR_TRUE; break;
00946               case kF10KeyCode:                                isSpecial = PR_TRUE; break;
00947               case kF11KeyCode:                                isSpecial = PR_TRUE; break;
00948               case kF12KeyCode:                                isSpecial = PR_TRUE; break;
00949               case kPauseKeyCode:                       isSpecial = PR_TRUE; break;
00950               case kScrollLockKeyCode:    isSpecial = PR_TRUE; break;
00951               case kPrintScreenKeyCode:   isSpecial = PR_TRUE; break;
00952 
00953               case kHelpKeyCode:                               isSpecial = PR_TRUE; break;
00954               case kDeleteKeyCode:                      isSpecial = PR_TRUE; break;
00955               case kTabKeyCode:                                       isSpecial = PR_TRUE; break;
00956               case kBackspaceKeyCode:     isSpecial = PR_TRUE; break;
00957 
00958               case kHomeKeyCode:                               isSpecial = PR_TRUE; break; 
00959               case kEndKeyCode:                                       isSpecial = PR_TRUE; break;
00960               case kPageUpKeyCode:                      isSpecial = PR_TRUE; break;
00961               case kPageDownKeyCode:                    isSpecial = PR_TRUE; break;
00962               case kLeftArrowKeyCode:                   isSpecial = PR_TRUE; break;
00963               case kRightArrowKeyCode:           isSpecial = PR_TRUE; break;
00964               case kUpArrowKeyCode:                            isSpecial = PR_TRUE; break;
00965               case kDownArrowKeyCode:                   isSpecial = PR_TRUE; break;
00966               case kReturnKeyCode:        isSpecial = PR_TRUE; break;
00967               case kEnterKeyCode:         isSpecial = PR_TRUE; break;
00968               case kPowerbookEnterKeyCode: isSpecial = PR_TRUE; break;
00969 
00970               default:                                                isSpecial = PR_FALSE; break;
00971        }
00972        return isSpecial;
00973 }
00974 
00975 
00976 //-------------------------------------------------------------------------
00977 //
00978 // ConvertKeyEventToUnicode
00979 //
00980 //-------------------------------------------------------------------------
00981 // we currently set the following to 5. We should fix this function later...
00982 #define UNICODE_BUFFER_SIZE_FOR_KEY 5
00983 PRUint32 nsMacEventHandler::ConvertKeyEventToUnicode(EventRecord& aOSEvent)
00984 {
00985        char charResult = aOSEvent.message & charCodeMask;
00986        
00987        //
00988        // get the script of text for Unicode conversion
00989        //
00990        ScriptCode textScript = (ScriptCode)GetScriptManagerVariable(smKeyScript);
00991 
00992        //
00993        // convert our script code (smKeyScript) to a TextEncoding 
00994        //
00995        TextEncoding textEncodingFromScript;
00996        OSErr err = ::UpgradeScriptInfoToTextEncoding(textScript, kTextLanguageDontCare, kTextRegionDontCare, nsnull,
00997                                                                              &textEncodingFromScript);
00998        NS_ASSERTION(err == noErr, "nsMacEventHandler::ConvertKeyEventToUnicode: UpgradeScriptInfoToTextEncoding failed.");
00999        if (err != noErr) return 0;
01000        
01001        TextToUnicodeInfo    textToUnicodeInfo;
01002        err = ::CreateTextToUnicodeInfoByEncoding(textEncodingFromScript,&textToUnicodeInfo);
01003        NS_ASSERTION(err == noErr, "nsMacEventHandler::ConvertKeyEventToUnicode: CreateUnicodeToTextInfoByEncoding failed.");
01004        if (err != noErr) return 0;
01005 
01006        //
01007        // convert to Unicode
01008        //
01009        ByteCount result_size, source_read;
01010        PRUnichar unicharResult[UNICODE_BUFFER_SIZE_FOR_KEY];
01011        err = ::ConvertFromTextToUnicode(textToUnicodeInfo,
01012                                                                sizeof(char),&charResult,
01013                                                                kUnicodeLooseMappingsMask,
01014                                                                0,NULL,NULL,NULL,
01015                                                                sizeof(PRUnichar)*UNICODE_BUFFER_SIZE_FOR_KEY,&source_read,
01016                                                                &result_size,NS_REINTERPRET_CAST(PRUint16*, unicharResult));
01017        ::DisposeTextToUnicodeInfo(&textToUnicodeInfo);
01018        NS_ASSERTION(err == noErr, "nsMacEventHandler::ConvertKeyEventToUnicode: ConverFromTextToUnicode failed.");
01019        // if we got the following result, then it mean we got more than one Unichar from it.
01020        NS_ASSERTION(result_size == 2, "nsMacEventHandler::ConvertKeyEventToUnicode: ConverFromTextToUnicode failed.");
01021        // Fix Me!!!
01022        // the result_size will not equal to 2 in the following cases:
01023        //
01024        // 1. Hebrew/Arabic scripts, when we convert ( ) { } [ ]  < >  etc. 
01025        // The TEC will produce result_size = 6 (3 PRUnichar*) :
01026        // one Right-To-Left-Mark, the char and one Left-To-Right-Mark
01027        // We should fix this later...
01028        // See the following URL for the details...
01029        // ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/APPLE/ARABIC.TXT
01030        // ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/APPLE/FARSI.TXT
01031        // ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/APPLE/HEBREW.TXT
01032        //
01033        // 2. Also, it probably won't work in Thai and Indic keyboard since one char may convert to
01034        // several PRUnichar. It sometimes add zwj or zwnj. See the following url for details.
01035        // ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/APPLE/DEVANAGA.TXT
01036        // ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/APPLE/GUJARATI.TXT
01037        // ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/APPLE/GURMUKHI.TXT
01038        // ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/APPLE/THAI.TXT
01039        
01040 //     if (err != noErr) return 0;
01041 // I think we should ignore the above error since we already have the result we want
01042 
01043        return unicharResult[0];
01044 }
01045 
01046 
01047 //
01048 // ConvertKeyEventToContextMenuEvent
01049 //
01050 // Take a key event and all of its attributes at convert it into
01051 // a context menu event. We want just about everything (focused
01052 // widget, etc) but a few things need to bt tweaked.
01053 //
01054 static void
01055 ConvertKeyEventToContextMenuEvent(const nsKeyEvent* inKeyEvent, nsMouseEvent* outCMEvent)
01056 {
01057   *(nsInputEvent*)outCMEvent = *(nsInputEvent*)inKeyEvent;
01058   
01059   outCMEvent->eventStructType = NS_MOUSE_EVENT;
01060   outCMEvent->message = NS_CONTEXTMENU_KEY;
01061   outCMEvent->isShift = outCMEvent->isControl = outCMEvent->isAlt = outCMEvent->isMeta = PR_FALSE;
01062   
01063   outCMEvent->clickCount = 0;
01064   outCMEvent->acceptActivation = PR_FALSE;
01065 }
01066 
01067 
01068 //
01069 // IsContextMenuKey
01070 //
01071 // Check if the event should be a context menu event instead. Currently,
01072 // that is a control-space.
01073 //
01074 static inline PRBool
01075 IsContextMenuKey(const nsKeyEvent& inKeyEvent)
01076 {
01077   enum { kContextMenuKey = ' ' } ;
01078 
01079   return ( inKeyEvent.charCode == kContextMenuKey && inKeyEvent.isControl &&
01080             !inKeyEvent.isShift && !inKeyEvent.isMeta && !inKeyEvent.isAlt );
01081 }
01082 
01083 
01084 //-------------------------------------------------------------------------
01085 //
01086 // HandleUKeyEvent
01087 //
01088 //-------------------------------------------------------------------------
01089 PRBool nsMacEventHandler::HandleUKeyEvent(const PRUnichar* text, long charCount, EventRecord& aOSEvent)
01090 {
01091   ClearLastMouseUp();
01092 
01093   // The focused widget changed in HandleKeyUpDownEvent, so no NS_KEY_PRESS
01094   // events should be generated.
01095   if (mKeyIgnore)
01096     return PR_FALSE;
01097 
01098   PRBool handled = PR_FALSE;
01099 
01100   // get the focused widget
01101   nsWindow* focusedWidget = mEventDispatchHandler->GetActive();
01102   if (!focusedWidget)
01103     focusedWidget = mTopLevelWidget;
01104   
01105   // simulate key press events
01106   if (!IsSpecialRaptorKey((aOSEvent.message & keyCodeMask) >> 8))
01107   {
01108     // it is a message with text, send all the unicode characters
01109     PRInt32 i;
01110     for (i = 0; i < charCount; i++)
01111     {
01112       nsKeyEvent keyPressEvent(PR_TRUE, NS_KEY_PRESS, nsnull);
01113       InitializeKeyEvent(keyPressEvent, aOSEvent, focusedWidget, NS_KEY_PRESS, PR_FALSE);
01114       keyPressEvent.charCode = text[i];
01115 
01116       // If keydown default was prevented, do same for keypress
01117       if (mKeyHandled)
01118         keyPressEvent.flags |= NS_EVENT_FLAG_NO_DEFAULT;
01119 
01120       // control key is special in that it doesn't give us letters
01121       // it generates a charcode of 0x01 for control-a
01122       // so we offset to do the right thing for gecko
01123       // this doesn't happen for us in InitializeKeyEvent because we pass
01124       // PR_FALSE so no character translation occurs.
01125       // I'm guessing we don't want to do the translation there because
01126       // translation already occurred for the string passed to this method.
01127       if (keyPressEvent.isControl && keyPressEvent.charCode <= 26)       
01128       {
01129         if (keyPressEvent.isShift)
01130           keyPressEvent.charCode += 'A' - 1;
01131         else
01132           keyPressEvent.charCode += 'a' - 1;
01133       }
01134 
01135       // this block of code is triggered when user presses
01136       // a combination such as command-shift-M
01137       if (keyPressEvent.isShift && keyPressEvent.charCode <= 'z' && keyPressEvent.charCode >= 'a') 
01138         keyPressEvent.charCode -= 32;
01139 
01140       // before we dispatch a key, check if it's the context menu key.
01141       // If so, send a context menu event instead.
01142       if ( IsContextMenuKey(keyPressEvent) ) {
01143         nsMouseEvent contextMenuEvent(PR_TRUE, 0, nsnull, nsMouseEvent::eReal);
01144         ConvertKeyEventToContextMenuEvent(&keyPressEvent, &contextMenuEvent);
01145         handled |= focusedWidget->DispatchWindowEvent(contextMenuEvent);
01146       }
01147       else {
01148         // Send ordinary keypresses
01149         handled |= focusedWidget->DispatchWindowEvent(keyPressEvent);
01150       }
01151     }
01152   }
01153   else {
01154     // "Special" keys, only send one event based on the keycode
01155     nsKeyEvent keyPressEvent(PR_TRUE, NS_KEY_PRESS, nsnull);
01156     InitializeKeyEvent(keyPressEvent, aOSEvent, focusedWidget, NS_KEY_PRESS, PR_FALSE);
01157     handled = focusedWidget->DispatchWindowEvent(keyPressEvent);
01158   }
01159   return handled;
01160 }
01161 
01162 #pragma mark -
01163 //-------------------------------------------------------------------------
01164 //
01165 // HandleActivateEvent
01166 //
01167 //-------------------------------------------------------------------------
01168 void nsMacEventHandler::HandleActivateEvent(EventRef aEvent)
01169 {
01170   ClearLastMouseUp();
01171 
01172   OSErr err;
01173   PRUint32 eventKind = ::GetEventKind(aEvent);
01174   PRBool isActive = (eventKind == kEventWindowActivated) ? PR_TRUE : PR_FALSE;
01175 
01176   // Be paranoid about deactivating the last-active window before activating
01177   // the new one, and about not handling activation for the already-active
01178   // window.
01179 
01180        if (isActive && sLastActive != this)
01181        {
01182               if (sLastActive) {
01183                      WindowRef oldWindow = NS_STATIC_CAST(WindowRef,
01184                       sLastActive->mTopLevelWidget->GetNativeData(NS_NATIVE_DISPLAY));
01185                      // Deactivating also causes HandleActivateEvent to
01186                      // be called on sLastActive with isActive = PR_FALSE,
01187                      // so sLastActive will be nsnull after this call.
01188                      ::ActivateWindow(oldWindow, PR_FALSE);
01189               }
01190 
01191               sLastActive = this;
01192 
01193               //
01194               // Activate The TSMDocument associated with this handler
01195               //
01196               if (mTSMDocument) {
01197                 // make sure we do not use input widnow even some other code turn it for default by calling 
01198                 // ::UseInputWindow(nsnull, TRUE); 
01199                 ::UseInputWindow(mTSMDocument, FALSE); 
01200                 err = ::ActivateTSMDocument(mTSMDocument);
01201               }
01202 
01203 #ifdef DEBUG_TSM
01204 #if 0
01205               NS_ASSERTION(err==noErr,"nsMacEventHandler::HandleActivateEvent: ActivateTSMDocument failed");
01206 #endif
01207               printf("nsEventHandler::HandleActivateEvent: ActivateTSMDocument[%p] %s return %d\n",mTSMDocument,
01208               (err==noErr)?"":"ERROR", err);
01209 #endif
01210               
01211               
01212               PRBool active;
01213               mTopLevelWidget->IsActive(&active);
01214               nsWindow*     focusedWidget = mTopLevelWidget;
01215               if (!active) {
01216                 mEventDispatchHandler->SetActivated(focusedWidget);
01217                 mTopLevelWidget->SetIsActive(PR_TRUE);
01218               }
01219               else if (!mEventDispatchHandler->GetActive()) {
01220                 NS_ASSERTION(0, "We think we're active, but there is no active widget!");
01221                 mEventDispatchHandler->SetActivated(focusedWidget);
01222               }
01223               
01224               // Twiddle menu bars
01225               nsIMenuBar* menuBar = focusedWidget->GetMenuBar();
01226               if (menuBar)
01227               {
01228                 menuBar->Paint();
01229               }
01230               else
01231               {
01232                 //ÄTODO:    if the focusedWidget doesn't have a menubar,
01233                 //                        look all the way up to the window
01234                 //                        until one of the parents has a menubar
01235               }
01236 
01237               // Mouse-moved events were not processed while the window was
01238               // inactive.  Grab the current mouse position and treat it as
01239               // a mouse-moved event would be.
01240               EventRecord eventRecord;
01241               ::ConvertEventRefToEventRecord(aEvent, &eventRecord);
01242               HandleMouseMoveEvent(eventRecord);
01243        }
01244        else if (!isActive && sLastActive == this)
01245        {
01246               sLastActive = nsnull;
01247 
01248               if (nsnull != gRollupListener && (nsnull != gRollupWidget) ) {
01249                      // If there's a widget to be rolled up, it's got to
01250                      // be attached to the active window, so it's OK to
01251                      // roll it up on any deactivate event without
01252                      // further checking.
01253                      gRollupListener->Rollup();
01254               }
01255               //
01256               // Deactivate the TSMDocument assoicated with this EventHandler
01257               //
01258               if (mTSMDocument) {
01259                 // We should call FixTSMDocument() before deactivate the window.
01260                 // see http://bugzilla.mozilla.gr.jp/show_bug.cgi?id=4135
01261                 ResetInputState();
01262                 // make sure we do not use input widnow even some other code turn it for default by calling 
01263                 // ::UseInputWindow(nsnull, TRUE); 
01264                 ::UseInputWindow(mTSMDocument, FALSE); 
01265                 err = ::DeactivateTSMDocument(mTSMDocument);
01266               }
01267 
01268 #ifdef DEBUG_TSM
01269               NS_ASSERTION((noErr==err)||(tsmDocNotActiveErr==err),"nsMacEventHandler::HandleActivateEvent: DeactivateTSMDocument failed");
01270               printf("nsEventHandler::HandleActivateEvent: DeactivateTSMDocument[%p] %s return %d\n",mTSMDocument,
01271               (err==noErr)?"":"ERROR", err);
01272 #endif
01273               // Dispatch an NS_DEACTIVATE event 
01274               mEventDispatchHandler->SetDeactivated(mTopLevelWidget);
01275               mTopLevelWidget->SetIsActive(PR_FALSE);
01276        }
01277 }
01278 
01279 
01280 //-------------------------------------------------------------------------
01281 //
01282 // ResizeEvent
01283 //
01284 //-------------------------------------------------------------------------
01285 PRBool nsMacEventHandler::ResizeEvent ( WindowRef inWindow )
01286 {
01287        Rect macRect;
01288        ::GetWindowPortBounds ( inWindow, &macRect );
01289        ::LocalToGlobal(&topLeft(macRect));
01290        ::LocalToGlobal(&botRight(macRect));
01291        mTopLevelWidget->Resize(macRect.right - macRect.left,
01292                                 macRect.bottom - macRect.top,
01293                                 PR_FALSE,
01294                                 PR_TRUE); // resize came from the UI via event
01295        if (nsnull != gRollupListener && (nsnull != gRollupWidget) )
01296               gRollupListener->Rollup();
01297        mTopLevelWidget->UserStateForResize(); // size a zoomed window and it's no longer zoomed
01298 
01299        return PR_TRUE;
01300 }
01301 
01302 
01303 //
01304 // Scroll
01305 //
01306 // Called from a mouseWheel carbon event, tell Gecko to scroll.
01307 // 
01308 PRBool
01309 nsMacEventHandler::Scroll(PRInt32 aDeltaY, PRInt32 aDeltaX,
01310                           PRBool aIsPixels, const Point& aMouseLoc,
01311                           nsWindow* aWindow, PRUint32 aModifiers) {
01312   PRBool resY = ScrollAxis(nsMouseScrollEvent::kIsVertical, aDeltaY,
01313                            aIsPixels, aMouseLoc, aWindow, aModifiers);
01314   PRBool resX = ScrollAxis(nsMouseScrollEvent::kIsHorizontal, aDeltaX,
01315                            aIsPixels, aMouseLoc, aWindow, aModifiers);
01316 
01317   return resY || resX;
01318 } // Scroll
01319 
01320 
01321 //
01322 // ScrollAxis
01323 //
01324 PRBool
01325 nsMacEventHandler::ScrollAxis(nsMouseScrollEvent::nsMouseScrollFlags aAxis,
01326                               PRInt32 aDelta, PRBool aIsPixels,
01327                               const Point& aMouseLoc, nsWindow* aWindow,
01328                               PRUint32 aModifiers)
01329 {
01330   // Only scroll active windows.  Treat popups as active.
01331   WindowRef windowRef = NS_STATIC_CAST(WindowRef,
01332                          mTopLevelWidget->GetNativeData(NS_NATIVE_DISPLAY));
01333   nsWindowType windowType;
01334   mTopLevelWidget->GetWindowType(windowType);
01335   if (!::IsWindowActive(windowRef) && windowType != eWindowType_popup)
01336     return PR_FALSE;
01337 
01338   // Figure out which widget should be scrolled by traversing the widget
01339   // hierarchy beginning at the root nsWindow.  aMouseLoc should be
01340   // relative to the origin of this nsWindow.  If the scroll event came
01341   // from an nsMacWindow, then aWindow should refer to that nsMacWindow.
01342   nsIWidget* widgetToScroll = aWindow->FindWidgetHit(aMouseLoc);
01343 
01344   // Not all scroll events for the window are over a widget.  Consider
01345   // the title bar.
01346   if (!widgetToScroll)
01347     return PR_FALSE;
01348 
01349   if (aDelta == 0) {
01350     // Don't need to do anything, but eat the event anyway.
01351     return PR_TRUE;
01352   }
01353 
01354   if (gRollupListener && gRollupWidget) {
01355     // Roll up the rollup widget if the scroll isn't targeted at it
01356     // (or one of its children) and the listener was told to do so.
01357 
01358     PRBool rollup = PR_FALSE;
01359     gRollupListener->ShouldRollupOnMouseWheelEvent(&rollup);
01360 
01361     if (rollup) {
01362       nsCOMPtr<nsIWidget> widgetOrAncestor = widgetToScroll;
01363       do {
01364         if (widgetOrAncestor == gRollupWidget) {
01365           rollup = PR_FALSE;
01366           break;
01367         }
01368       } while (widgetOrAncestor = widgetOrAncestor->GetParent());
01369     }
01370 
01371     if (rollup)
01372       gRollupListener->Rollup();
01373   }
01374 
01375   nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, widgetToScroll);
01376 
01377   // The direction we get from the carbon event is opposite from the way
01378   // mozilla looks at it.  Reverse the direction.
01379   scrollEvent.delta = -aDelta;
01380 
01381   // If the scroll event comes from a mouse that only has a scroll wheel for
01382   // the vertical axis, and the shift key is held down, the system presents
01383   // it as a horizontal scroll and doesn't clear the shift key bit from
01384   // aModifiers.  The Mac is supposed to scroll horizontally in such a case.
01385   //
01386   // If the scroll event comes from a mouse that can scroll both axes, the
01387   // system doesn't apply any of this shift-key fixery.
01388   scrollEvent.scrollFlags = aAxis;
01389 
01390   if (aIsPixels)
01391     scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsPixels;
01392 
01393   // convert window-relative (local) mouse coordinates to widget-relative
01394   // coords for Gecko.
01395   nsPoint mouseLocRelativeToWidget(aMouseLoc.h, aMouseLoc.v);
01396   nsRect bounds;
01397   widgetToScroll->GetBounds(bounds);
01398   nsPoint widgetOrigin(bounds.x, bounds.y);
01399   widgetToScroll->ConvertToDeviceCoordinates(widgetOrigin.x, widgetOrigin.y);
01400   mouseLocRelativeToWidget.MoveBy(-widgetOrigin.x, -widgetOrigin.y);
01401 
01402   scrollEvent.point.x = mouseLocRelativeToWidget.x;
01403   scrollEvent.point.y = mouseLocRelativeToWidget.y;
01404   scrollEvent.time = PR_IntervalNow();
01405 
01406   // Translate OS event modifiers into Gecko event modifiers
01407   scrollEvent.isShift   = ((aModifiers & shiftKey)   != 0);
01408   scrollEvent.isControl = ((aModifiers & controlKey) != 0);
01409   scrollEvent.isAlt     = ((aModifiers & optionKey)  != 0);
01410   scrollEvent.isMeta    = ((aModifiers & cmdKey)     != 0);
01411 
01412   nsEventStatus status;
01413   widgetToScroll->DispatchEvent(&scrollEvent, status);
01414 
01415   return nsWindow::ConvertStatus(status);
01416 } // ScrollAxis
01417 
01418 
01419 //-------------------------------------------------------------------------
01420 //
01421 // HandleMouseDownEvent
01422 //
01423 //-------------------------------------------------------------------------
01424 PRBool nsMacEventHandler::HandleMouseDownEvent(EventRecord&    aOSEvent)
01425 {    
01426        PRBool retVal = PR_FALSE;
01427 
01428        WindowPtr            whichWindow;
01429        short partCode = ::FindWindow(aOSEvent.where, &whichWindow);
01430 
01431   PRBool ignoreClickInContent = PR_FALSE;
01432 
01433   // Deal with any popups (comboboxes, xul popups, XP menus, etc) that might have to 
01434   // be closed down since they are implemented as stand-alone windows on top of
01435   // the current content window. If the click is not in the front window, we need to
01436   // hide the popup if one is visible. Furthermore, we want to ignore the click that
01437   // caused the popup to close and not pass it along to gecko.
01438   if ( whichWindow != ::FrontWindow() ) {
01439     if ( gRollupListener && gRollupWidget ) {
01440       PRBool rollup = PR_TRUE;
01441 
01442       // if we're dealing with menus, we probably have submenus and we don't want
01443       // to rollup if the click is in a parent menu of the current submenu.
01444       nsCOMPtr<nsIMenuRollup> menuRollup ( do_QueryInterface(gRollupListener) );
01445       if ( menuRollup ) {
01446         nsCOMPtr<nsISupportsArray> widgetChain;
01447         menuRollup->GetSubmenuWidgetChain ( getter_AddRefs(widgetChain) );
01448         if ( widgetChain ) {      
01449           PRUint32 count = 0;
01450           widgetChain->Count(&count);
01451           for ( PRUint32 i = 0; i < count; ++i ) {
01452             nsCOMPtr<nsISupports> genericWidget;
01453             widgetChain->GetElementAt ( i, getter_AddRefs(genericWidget) );
01454             nsCOMPtr<nsIWidget> widget ( do_QueryInterface(genericWidget) );
01455             if ( widget ) {
01456               if ( NS_REINTERPRET_CAST(WindowPtr,widget->GetNativeData(NS_NATIVE_DISPLAY)) == whichWindow )
01457                  rollup = PR_FALSE;
01458             }         
01459           } // foreach parent menu widget
01460         }
01461       } // if rollup listener knows about menus
01462       
01463       // if we've determined that we should still rollup everything, do it.
01464       if ( rollup ) {
01465                      gRollupListener->Rollup();
01466                      ignoreClickInContent = PR_TRUE;
01467          }
01468  
01469               } // if a popup is active
01470   } // if click in a window not the frontmost
01471  
01472        switch (partCode)
01473        {
01474               case inDrag:
01475               {
01476                      Point macPoint;
01477                      Rect portRect;
01478                      ::GetWindowPortBounds(whichWindow, &portRect);
01479                      macPoint = topLeft(portRect);
01480                      ::LocalToGlobal(&macPoint);
01481                      mTopLevelWidget->MoveToGlobalPoint(macPoint.h, macPoint.v);
01482                      retVal = PR_TRUE;
01483                      break;
01484               }
01485 
01486               case inGrow:
01487               {
01488       ResizeEvent ( whichWindow );
01489       retVal = PR_TRUE;
01490       break;
01491               }
01492 
01493               case inGoAway:
01494               {
01495                      ResetInputState();   // IM:TEXT 7-23 said we need to call FixTSMDocument when we go away...
01496                      if (nsnull != gRollupListener && (nsnull != gRollupWidget) ) {
01497                             gRollupListener->Rollup();
01498                      }
01499                      mEventDispatchHandler->DispatchGuiEvent(mTopLevelWidget, NS_XUL_CLOSE);             
01500                      // mTopLevelWidget->Destroy(); (this, by contrast, would immediately close the window)
01501                      retVal = PR_TRUE;
01502                      break;
01503               }
01504 
01505               case inContent:
01506               {
01507                      // don't allow clicks that rolled up a popup through to the content area.
01508                      if ( ignoreClickInContent )
01509                             break;
01510                                           
01511                      nsMouseEvent mouseEvent(PR_TRUE, 0, nsnull, nsMouseEvent::eReal);
01512                      PRUint32 mouseButton = NS_MOUSE_LEFT_BUTTON_DOWN;
01513                      if ( aOSEvent.modifiers & controlKey )
01514                        mouseButton = NS_MOUSE_RIGHT_BUTTON_DOWN;
01515 
01516                      // We've hacked our events to include the button.
01517                      // Normally message is undefined in mouse click/drag events.
01518                      if ( aOSEvent.message == kEventMouseButtonSecondary )
01519                        mouseButton = NS_MOUSE_RIGHT_BUTTON_DOWN;
01520                      if ( aOSEvent.message == kEventMouseButtonTertiary )
01521                        mouseButton = NS_MOUSE_MIDDLE_BUTTON_DOWN;
01522 
01523                      ConvertOSEventToMouseEvent(aOSEvent, mouseEvent, mouseButton);
01524 
01525                      nsCOMPtr<nsIWidget> kungFuDeathGrip ( mouseEvent.widget );            // ensure widget doesn't go away
01526                      nsWindow* widgetHit = NS_STATIC_CAST(nsWindow*, mouseEvent.widget);   //   while we're processing event
01527                      if (widgetHit)
01528                      {        
01529                             // set the activation and focus on the widget hit, if it accepts it
01530                             {
01531                                    nsMouseEvent mouseActivateEvent(PR_TRUE, 0, nsnull,
01532                                           nsMouseEvent::eReal);
01533           ConvertOSEventToMouseEvent(aOSEvent, mouseActivateEvent, NS_MOUSE_ACTIVATE);
01534                                    widgetHit->DispatchMouseEvent(mouseActivateEvent);
01535                             }
01536 
01537                             // dispatch the event
01538                             retVal = widgetHit->DispatchMouseEvent(mouseEvent);
01539                             
01540                             // if we're a control-click, send in an additional NS_CONTEXTMENU event
01541                             // after the mouse down.
01542                             if ( mouseButton == NS_MOUSE_RIGHT_BUTTON_DOWN ) {
01543                      nsMouseEvent contextMenuEvent(PR_TRUE, 0, nsnull,
01544                                         nsMouseEvent::eReal);
01545                      ConvertOSEventToMouseEvent(aOSEvent, contextMenuEvent, NS_CONTEXTMENU);
01546                      contextMenuEvent.isControl = PR_FALSE;                         
01547                                    widgetHit->DispatchMouseEvent(contextMenuEvent);
01548         } 
01549 
01550         // If we found a widget to dispatch to, say we handled the event.
01551         // The meaning of the result of DispatchMouseEvent() is ambiguous.
01552         // In Gecko terms, it means "continue processing", but that doesn't
01553         // say if the event was really handled (which is a simplistic notion
01554         // to Gecko).
01555         retVal = PR_TRUE;
01556                      }
01557                                           
01558                      mEventDispatchHandler->SetWidgetHit(widgetHit);
01559                      mMouseInWidgetHit = PR_TRUE;
01560                      break;
01561               }
01562 
01563 
01564               case inZoomIn:
01565               case inZoomOut:
01566               {
01567                      mEventDispatchHandler->DispatchSizeModeEvent(mTopLevelWidget,
01568                             partCode == inZoomIn ? nsSizeMode_Normal : nsSizeMode_Maximized);
01569                      retVal = PR_TRUE;
01570                      break;
01571               }
01572 
01573     case inToolbarButton:           // we get this part on Mac OS X only
01574       mEventDispatchHandler->DispatchGuiEvent(mTopLevelWidget, NS_OS_TOOLBAR);             
01575       retVal = PR_TRUE;
01576       break;
01577        }
01578        return retVal;
01579 }
01580 
01581 
01582 //-------------------------------------------------------------------------
01583 //
01584 // HandleMouseUpEvent
01585 //
01586 //-------------------------------------------------------------------------
01587 PRBool nsMacEventHandler::HandleMouseUpEvent(
01588                                                                                                   EventRecord&         aOSEvent)
01589 {
01590        PRBool retVal = PR_FALSE;
01591 
01592        nsMouseEvent mouseEvent(PR_TRUE, 0, nsnull, nsMouseEvent::eReal);
01593        PRUint32 mouseButton = NS_MOUSE_LEFT_BUTTON_UP;
01594 
01595        // We've hacked our events to include the button.
01596        // Normally message is undefined in mouse click/drag events.
01597        if ( aOSEvent.message == kEventMouseButtonSecondary )
01598               mouseButton = NS_MOUSE_RIGHT_BUTTON_UP;
01599        if ( aOSEvent.message == kEventMouseButtonTertiary )
01600               mouseButton = NS_MOUSE_MIDDLE_BUTTON_UP;
01601 
01602        ConvertOSEventToMouseEvent(aOSEvent, mouseEvent, mouseButton);
01603 
01604        nsWindow* widgetReleased = (nsWindow*)mouseEvent.widget;
01605        nsWindow* widgetHit = mEventDispatchHandler->GetWidgetHit();
01606 
01607        if ( widgetReleased )
01608        {
01609               widgetReleased->DispatchMouseEvent(mouseEvent);
01610               // If we found a widget to dispatch the event to, say that we handled it
01611               // (see comments in HandleMouseDownEvent()).
01612               retVal = PR_TRUE;
01613        }
01614        
01615        if ( widgetReleased != widgetHit ) {
01616          //XXX we should send a mouse exit event to the last widget, right?!?! But
01617          //XXX we cannot use the same event, because the coordinates we just
01618          //XXX computed are in the wrong window/widget coordinate space. I'm 
01619          //XXX unclear what we should do in this case. (pinkerton).
01620        }
01621        
01622        mEventDispatchHandler->SetWidgetHit(nsnull);
01623 
01624        return retVal;
01625 }
01626 
01627 
01628 //-------------------------------------------------------------------------
01629 //
01630 // HandleMouseMoveEvent
01631 //
01632 //-------------------------------------------------------------------------
01633 PRBool nsMacEventHandler::HandleMouseMoveEvent( EventRecord& aOSEvent )
01634 {
01635        nsWindow* lastWidgetHit = mEventDispatchHandler->GetWidgetHit();
01636        nsWindow* lastWidgetPointed = mEventDispatchHandler->GetWidgetPointed();
01637   
01638        PRBool retVal = PR_FALSE;
01639 
01640        WindowRef wind = reinterpret_cast<WindowRef>(mTopLevelWidget->GetNativeData(NS_NATIVE_DISPLAY));
01641        nsWindowType windowType;
01642        mTopLevelWidget->GetWindowType(windowType);
01643        if (!::IsWindowActive(wind) && windowType != eWindowType_popup)
01644               return retVal;
01645 
01646        nsMouseEvent mouseEvent(PR_TRUE, 0, nsnull, nsMouseEvent::eReal);
01647        ConvertOSEventToMouseEvent(aOSEvent, mouseEvent, NS_MOUSE_MOVE);
01648        if (lastWidgetHit)
01649        {
01650               Point macPoint = aOSEvent.where;
01651               nsGraphicsUtils::SafeSetPortWindowPort(wind);
01652               {
01653                      StOriginSetter  originSetter(wind);
01654                      ::GlobalToLocal(&macPoint);
01655               }
01656               PRBool inWidgetHit = lastWidgetHit->PointInWidget(macPoint);
01657               if (mMouseInWidgetHit != inWidgetHit)
01658               {
01659                      mMouseInWidgetHit = inWidgetHit;
01660                      mouseEvent.message = (inWidgetHit ? NS_MOUSE_ENTER : NS_MOUSE_EXIT);
01661               }
01662               lastWidgetHit->DispatchMouseEvent(mouseEvent);
01663               retVal = PR_TRUE;
01664        }
01665        else
01666        {
01667               nsWindow* widgetPointed = (nsWindow*)mouseEvent.widget;
01668               nsCOMPtr<nsIWidget> kungFuDeathGrip(widgetPointed);     // Protect during processing
01669               if (widgetPointed != lastWidgetPointed)
01670               {
01671                      if (lastWidgetPointed)
01672                      {
01673         // We need to convert the coords to be relative to lastWidgetPointed.
01674         nsPoint widgetHitPoint = mouseEvent.point;
01675 
01676         Point macPoint = aOSEvent.where;
01677         nsGraphicsUtils::SafeSetPortWindowPort(wind);
01678 
01679         {
01680           StOriginSetter originSetter(wind);
01681           ::GlobalToLocal(&macPoint);
01682         }
01683 
01684         nsPoint lastWidgetHitPoint(macPoint.h, macPoint.v);
01685 
01686           nsRect bounds;
01687           lastWidgetPointed->GetBounds(bounds);
01688           nsPoint widgetOrigin(bounds.x, bounds.y);
01689           lastWidgetPointed->LocalToWindowCoordinate(widgetOrigin);
01690           lastWidgetHitPoint.MoveBy(-widgetOrigin.x, -widgetOrigin.y);
01691                             mouseEvent.widget = lastWidgetPointed;
01692                             mouseEvent.point = lastWidgetHitPoint;
01693                             mouseEvent.message = NS_MOUSE_EXIT;
01694                             lastWidgetPointed->DispatchMouseEvent(mouseEvent);
01695                             retVal = PR_TRUE;
01696 
01697                             mouseEvent.point = widgetHitPoint;
01698                      }
01699 
01700       mEventDispatchHandler->SetWidgetPointed(widgetPointed);
01701 #if TRACK_MOUSE_LOC
01702       mEventDispatchHandler->SetGlobalPoint(aOSEvent.where);
01703 #endif
01704 
01705                      if (widgetPointed)
01706                      {
01707                             mouseEvent.widget = widgetPointed;
01708                             mouseEvent.message = NS_MOUSE_ENTER;
01709                             widgetPointed->DispatchMouseEvent(mouseEvent);
01710                             retVal = PR_TRUE;
01711                      }
01712               }
01713               else
01714               {
01715                      if (widgetPointed)
01716                      {
01717                             widgetPointed->DispatchMouseEvent(mouseEvent);
01718                             retVal = PR_TRUE;
01719                      }
01720               }
01721        }
01722 
01723        return retVal;
01724 }
01725 
01726 
01727 #pragma mark -
01728 //-------------------------------------------------------------------------
01729 //
01730 // ConvertOSEventToMouseEvent
01731 //
01732 //-------------------------------------------------------------------------
01733 void nsMacEventHandler::ConvertOSEventToMouseEvent(
01734                                                                                                   EventRecord&         aOSEvent,
01735                                                                                                   nsMouseEvent&        aMouseEvent,
01736                                                                                                   PRUint32                           aMessage)
01737 {
01738        // we're going to time double-clicks from mouse *up* to next mouse *down*
01739        if (aMessage == NS_MOUSE_LEFT_BUTTON_UP  ||
01740       aMessage == NS_MOUSE_RIGHT_BUTTON_UP ||
01741       aMessage == NS_MOUSE_MIDDLE_BUTTON_UP)
01742        {
01743               // remember when this happened for the next mouse down
01744               mLastMouseUpWhen = aOSEvent.when;
01745               mLastMouseUpWhere = aOSEvent.where;
01746        }
01747        else if (aMessage == NS_MOUSE_LEFT_BUTTON_DOWN  ||
01748            aMessage == NS_MOUSE_RIGHT_BUTTON_DOWN ||
01749            aMessage == NS_MOUSE_MIDDLE_BUTTON_DOWN)
01750        {
01751               // now look to see if we want to convert this to a double- or triple-click
01752               const short kDoubleClickMoveThreshold     = 5;
01753               
01754               if (((aOSEvent.when - mLastMouseUpWhen) < ::GetDblTime()) &&
01755                             (((abs(aOSEvent.where.h - mLastMouseUpWhere.h) < kDoubleClickMoveThreshold) &&
01756                                    (abs(aOSEvent.where.v - mLastMouseUpWhere.v) < kDoubleClickMoveThreshold))))
01757               {             
01758                      mClickCount ++;
01759                      
01760 //                   if (mClickCount == 2)
01761 //                          aMessage = NS_MOUSE_LEFT_DOUBLECLICK;
01762               }
01763               else
01764               {
01765                      // reset the click count, to count *this* click
01766                      mClickCount = 1;
01767               }
01768        }
01769 
01770        // get the widget hit and the hit point inside that widget
01771        nsWindowType wtype;
01772        mTopLevelWidget->GetWindowType(wtype);
01773        PRBool          topLevelIsAPopup = (wtype == eWindowType_popup);
01774        WindowRef       eventTargetWindow = reinterpret_cast<WindowRef>(mTopLevelWidget->GetNativeData(NS_NATIVE_DISPLAY));
01775 
01776        WindowPtr       windowThatHasEvent = nsnull;
01777        ControlPartCode partCode = ::FindWindow(aOSEvent.where, &windowThatHasEvent);
01778 
01779        // if the mouse button is still down, send events to the last widget hit unless the
01780        // new event is in a popup window.
01781        nsWindow* lastWidgetHit = mEventDispatchHandler->GetWidgetHit();
01782        nsWindow* widgetHit = nsnull;
01783        if (lastWidgetHit)
01784        {
01785         // make sure we in the same window as where we started before we go assuming
01786         // that we know where the event will go.
01787         WindowRef   lastWind = reinterpret_cast<WindowRef>(lastWidgetHit->GetNativeData(NS_NATIVE_DISPLAY));
01788         PRBool      eventInSameWindowAsLastEvent = (windowThatHasEvent == lastWind);
01789         if ( eventInSameWindowAsLastEvent || !topLevelIsAPopup ) {      
01790             if (::StillDown() || aMessage == NS_MOUSE_LEFT_BUTTON_UP)
01791             {
01792                 widgetHit = lastWidgetHit;
01793                 eventTargetWindow = lastWind;   // make sure we use the correct window to fix the coords
01794             }
01795             else
01796             {
01797                 // Some widgets can eat mouseUp events (text widgets in TEClick, sbars in TrackControl).
01798                 // In that case, stop considering this widget as being still hit.
01799                 mEventDispatchHandler->SetWidgetHit(nsnull);
01800             }
01801         }
01802        }
01803 
01804        Point hitPoint = aOSEvent.where;
01805        nsGraphicsUtils::SafeSetPortWindowPort(eventTargetWindow);
01806 
01807        {
01808            StOriginSetter  originSetter(eventTargetWindow);
01809        ::GlobalToLocal(&hitPoint);     // gives the mouse loc in local coords of the hit window
01810        }
01811        
01812        nsPoint widgetHitPoint(hitPoint.h, hitPoint.v);
01813 
01814        // if the mouse is in the grow box, pretend that it has left the window
01815        if ( partCode != inGrow ) {
01816               if (! widgetHit)
01817                      widgetHit = mTopLevelWidget->FindWidgetHit(hitPoint);
01818        
01819               if (widgetHit)
01820               {
01821                      nsRect bounds;
01822                      widgetHit->GetBounds(bounds);
01823                      nsPoint widgetOrigin(bounds.x, bounds.y);
01824                      widgetHit->LocalToWindowCoordinate(widgetOrigin);
01825                      widgetHitPoint.MoveBy(-widgetOrigin.x, -widgetOrigin.y);
01826               }
01827        }
01828 
01829     // if we haven't found anything and we're tracking the mouse for a popup, then
01830     // it's probable that the coordinates are just negative and we were dispatched
01831     // here just cuz we're the top window in the app right now. In that case, just
01832     // set the widget hit to this one. It's harmless (I hope), and it avoids asserts
01833     // in the view code about null widgets.
01834     if ( !widgetHit && topLevelIsAPopup && (hitPoint.h < 0 || hitPoint.v < 0) )
01835         widgetHit = mTopLevelWidget;
01836 
01837     InitializeMouseEvent(aMouseEvent, widgetHitPoint, aOSEvent.modifiers,
01838                          mClickCount);
01839 
01840     // nsEvent
01841     aMouseEvent.message     = aMessage;
01842 
01843     // nsGUIEvent
01844     aMouseEvent.widget      = widgetHit;
01845     aMouseEvent.nativeMsg   = (void*)&aOSEvent;
01846 
01847     // nsMouseEvent
01848     aMouseEvent.acceptActivation = PR_TRUE;
01849 }
01850 
01851 //-------------------------------------------------------------------------
01852 //
01853 // HandlePositionToOffsetEvent
01854 //
01855 //-------------------------------------------------------------------------
01856 long nsMacEventHandler::HandlePositionToOffset(Point aPoint,short* regionClass)
01857 {
01858        *regionClass = kTSMOutsideOfBody;
01859        return 0;
01860 }
01861 
01862 //-------------------------------------------------------------------------
01863 //
01864 // HandleOffsetToPosition Event
01865 //
01866 //-------------------------------------------------------------------------
01867 nsresult nsMacEventHandler::HandleOffsetToPosition(long offset,Point* thePoint)
01868 {
01869        thePoint->v = mIMEPos.y;
01870        thePoint->h = mIMEPos.x;
01871        //printf("local (x,y) = (%d, %d)\n", thePoint->h, thePoint->v);
01872        WindowRef wind = reinterpret_cast<WindowRef>(mTopLevelWidget->GetNativeData(NS_NATIVE_DISPLAY));
01873        nsGraphicsUtils::SafeSetPortWindowPort(wind);
01874        Rect savePortRect;
01875        ::GetWindowPortBounds(wind, &savePortRect);
01876        ::LocalToGlobal(thePoint);
01877        //printf("global (x,y) = (%d, %d)\n", thePoint->h, thePoint->v);
01878 
01879        return PR_TRUE;
01880 }
01881 
01882 //-------------------------------------------------------------------------
01883 //
01884 // HandleUpdate Event
01885 //
01886 //-------------------------------------------------------------------------
01887 nsresult nsMacEventHandler::UnicodeHandleUpdateInputArea(const PRUnichar* text, long charCount,
01888                                                          long fixedLength, TextRangeArray* textRangeList)
01889 {
01890 #ifdef DEBUG_TSM
01891   printf("********************************************************************************\n");
01892   printf("nsMacEventHandler::UnicodeHandleUpdateInputArea size=%d fixlen=%d\n",charCount, fixedLength);
01893 #endif
01894   nsresult res = NS_OK;
01895   long committedLen = 0;
01896   //------------------------------------------------------------------------------------------------
01897   // if we aren't in composition mode alredy, signal the backing store w/ the mode change
01898   //------------------------------------------------------------------------------------------------
01899   if (!mIMEIsComposing) {
01900     res = HandleStartComposition();
01901     NS_ASSERTION(NS_SUCCEEDED(res), "nsMacEventHandler::UnicodeHandleUpdateInputArea: HandleStartComposition failed.");
01902     if (NS_FAILED(res))
01903       goto error;
01904   }
01905   // mIMECompositionStr should be created in the HandleStartComposition
01906   NS_ASSERTION(mIMECompositionStr, "do not have mIMECompositionStr");
01907   if (nsnull == mIMECompositionStr)
01908   {
01909     res = NS_ERROR_OUT_OF_MEMORY;
01910     goto error;
01911   }
01912 
01913   //====================================================================================================
01914   // Note- It is possible that the UpdateInputArea event sent both committed text and uncommitted text
01915   // at the same time. The easiest way to do that is using Korean input method w/ "Enter by Character" option
01916   //====================================================================================================
01917   //  1. Handle the committed text
01918   //====================================================================================================
01919   committedLen = (fixedLength == -1) ? charCount : fixedLength;
01920   if (0 != committedLen)
01921   {
01922 #ifdef DEBUG_TSM
01923     printf("Have commit text from 0 to %d\n", committedLen);
01924 #endif
01925     //------------------------------------------------------------------------------------------------
01926     // 1.1 send textEvent to commit the text
01927     //------------------------------------------------------------------------------------------------
01928     mIMECompositionStr->Assign(text, committedLen);
01929 #ifdef DEBUG_TSM
01930     printf("1.2====================================\n");
01931 #endif
01932     res = HandleTextEvent(0, nsnull);
01933     NS_ASSERTION(NS_SUCCEEDED(res), "nsMacEventHandler::UnicodeHandleUpdateInputArea: HandleTextEvent failed.");
01934     if (NS_FAILED(res)) 
01935       goto error; 
01936     //------------------------------------------------------------------------------------------------
01937     // 1.3 send compositionEvent to end the composition
01938     //------------------------------------------------------------------------------------------------
01939     res = nsMacEventHandler::HandleEndComposition();
01940     NS_ASSERTION(NS_SUCCEEDED(res), "nsMacEventHandler::UnicodeHandleUpdateInputArea: HandleEndComposition failed.");
01941     if (NS_FAILED(res)) 
01942       goto error; 
01943   }    //  1. Handle the committed text
01944 
01945   //====================================================================================================
01946   //  2. Handle the uncommitted text
01947   //====================================================================================================
01948   if ((-1 != fixedLength) && (charCount != fixedLength))
01949   {  
01950 #ifdef DEBUG_TSM
01951     printf("Have new uncommitted text from %d to text_size(%d)\n", committedLen, charCount);
01952 #endif
01953     //------------------------------------------------------------------------------------------------
01954     // 2.1 send compositionEvent to start the composition
01955     //------------------------------------------------------------------------------------------------
01956     //
01957     // if we aren't in composition mode already, signal the backing store w/ the mode change
01958     //  
01959     if (!mIMEIsComposing) {
01960       res = HandleStartComposition();
01961       NS_ASSERTION(NS_SUCCEEDED(res), "nsMacEventHandler::UnicodeHandleUpdateInputArea: HandleStartComposition failed.");
01962       if (NS_FAILED(res))
01963         goto error; 
01964     }   // 2.1 send compositionEvent to start the composition
01965     //------------------------------------------------------------------------------------------------
01966     // 2.2 send textEvent for the uncommitted text
01967     //------------------------------------------------------------------------------------------------
01968     //------------------------------------------------------------------------------------------------
01969     // 2.2.1 make sure we have one range array
01970     //------------------------------------------------------------------------------------------------
01971 
01972     TextRangeArray rawTextRangeArray;
01973     TextRangeArray *rangeArray;
01974     if (textRangeList && textRangeList->fNumOfRanges) {
01975       rangeArray = textRangeList;
01976     } else {
01977       rangeArray = &rawTextRangeArray;
01978       rawTextRangeArray.fNumOfRanges = 1;
01979       rawTextRangeArray.fRange[0].fStart = committedLen * 2;
01980       rawTextRangeArray.fRange[0].fEnd = charCount * 2;
01981       rawTextRangeArray.fRange[0].fHiliteStyle = NS_TEXTRANGE_RAWINPUT;      
01982     }
01983 
01984     
01985 #ifdef DEBUG_TSM
01986     printf("nsMacEventHandler::UnicodeHandleUpdateInputArea textRangeList is %s\n", textRangeList ? "NOT NULL" : "NULL");
01987 #endif
01988     nsTextRangeArray xpTextRangeArray = new nsTextRange[rangeArray->fNumOfRanges];
01989     NS_ASSERTION(xpTextRangeArray!=NULL, "nsMacEventHandler::UnicodeHandleUpdateInputArea: xpTextRangeArray memory allocation failed.");
01990     if (xpTextRangeArray == NULL)
01991     {
01992       res = NS_ERROR_OUT_OF_MEMORY;
01993       goto error; 
01994     }
01995   
01996     //------------------------------------------------------------------------------------------------
01997     // 2.2.2 convert range array into our xp range array
01998     //------------------------------------------------------------------------------------------------
01999     //
02000     // the TEC offset mapping capabilities won't work here because you need to have unique, ordered offsets
02001     //  so instead we iterate over the range list and map each range individually.  it's probably faster than
02002     //  trying to do collapse all the ranges into a single offset list
02003     //
02004     PRInt32 i;
02005     for(i = 0; i < rangeArray->fNumOfRanges; i++) {      
02006       // 2.2.2.1 check each range item in NS_ASSERTION
02007       NS_ASSERTION(
02008         (NS_TEXTRANGE_CARETPOSITION==rangeArray->fRange[i].fHiliteStyle)||
02009         (NS_TEXTRANGE_RAWINPUT==rangeArray->fRange[i].fHiliteStyle)||
02010         (NS_TEXTRANGE_SELECTEDRAWTEXT==rangeArray->fRange[i].fHiliteStyle)||
02011         (NS_TEXTRANGE_CONVERTEDTEXT==rangeArray->fRange[i].fHiliteStyle)||
02012         (NS_TEXTRANGE_SELECTEDCONVERTEDTEXT==rangeArray->fRange[i].fHiliteStyle),
02013         "illegal range type");
02014       NS_ASSERTION( rangeArray->fRange[i].fStart/2 <= charCount, "illegal range");
02015       NS_ASSERTION( rangeArray->fRange[i].fEnd/2 <= charCount, "illegal range");
02016 
02017 #ifdef DEBUG_TSM
02018       printf("nsMacEventHandler::UnicodeHandleUpdateInputArea textRangeList[%d] = (%d,%d) text_size = %d\n",i,
02019         rangeArray->fRange[i].fStart/2, rangeArray->fRange[i].fEnd/2, charCount);
02020 #endif      
02021       // 2.2.2.6 put destinationOffset into xpTextRangeArray[i].mStartOffset 
02022       xpTextRangeArray[i].mRangeType = rangeArray->fRange[i].fHiliteStyle;
02023       xpTextRangeArray[i].mStartOffset = rangeArray->fRange[i].fStart / 2;
02024       xpTextRangeArray[i].mEndOffset   = rangeArray->fRange[i].fEnd / 2;
02025 
02026       // 2.2.2.7 Check the converted result in NS_ASSERTION
02027 #ifdef DEBUG_TSM
02028       printf("nsMacEventHandler::UnicodeHandleUpdateInputArea textRangeList[%d] => type=%d (%d,%d)\n",i,
02029         xpTextRangeArray[i].mRangeType,
02030         xpTextRangeArray[i].mStartOffset, xpTextRangeArray[i].mEndOffset);
02031 #endif      
02032 
02033       NS_ASSERTION((NS_TEXTRANGE_CARETPOSITION!=xpTextRangeArray[i].mRangeType) ||
02034              (xpTextRangeArray[i].mStartOffset == xpTextRangeArray[i].mEndOffset),
02035              "start != end in CaretPosition");
02036     }
02037     mIMECompositionStr->Assign(text+committedLen, charCount-committedLen);
02038     //------------------------------------------------------------------------------------------------
02039     // 2.2.4 send the text event
02040     //------------------------------------------------------------------------------------------------
02041 #ifdef DEBUG_TSM
02042       printf("2.2.4====================================\n");
02043 #endif      
02044 
02045     res = HandleTextEvent(rangeArray->fNumOfRanges,xpTextRangeArray);
02046     NS_ASSERTION(NS_SUCCEEDED(res), "nsMacEventHandler::UnicodeHandleUpdateInputArea: HandleTextEvent failed.");
02047     if (NS_FAILED(res)) 
02048       goto error; 
02049     delete [] xpTextRangeArray;
02050   } //  2. Handle the uncommitted text
02051   else if ((0==charCount) && (0==fixedLength))
02052   {
02053     // 3. Handle empty text event
02054     // This is needed when we input some uncommitted text, and then delete all of them
02055     // When the last delete come, we will got a text_size = 0 and fixedLength = 0
02056     // In that case, we need to send a text event to clean up the input hole....
02057     mIMECompositionStr->Truncate();      
02058 #ifdef DEBUG_TSM
02059       printf("3.====================================\n");
02060 #endif
02061     // 3.1 send the empty text event.
02062     res = HandleTextEvent(0, nsnull);
02063     NS_ASSERTION(NS_SUCCEEDED(res),"nsMacEventHandler::UnicodeHandleUpdateInputArea: HandleTextEvent failed.");
02064     if (NS_FAILED(res)) 
02065       goto error; 
02066     // 3.2 send an endComposition event, we need this to make sure the delete after this work properly.
02067     res = nsMacEventHandler::HandleEndComposition();
02068     NS_ASSERTION(NS_SUCCEEDED(res),"nsMacEventHandler::UnicodeHandleUpdateInputArea: HandleEndComposition failed.");
02069     if (NS_FAILED(res)) 
02070       goto error;     
02071   }
02072   
02073 error:
02074   return res;
02075 }
02076 
02077 nsresult nsMacEventHandler::HandleUnicodeGetSelectedText(nsAString& outString)
02078 {
02079   outString.Truncate(0);
02080   nsWindow* focusedWidget = mEventDispatchHandler->GetActive();
02081   if (!focusedWidget)
02082     focusedWidget = mTopLevelWidget;
02083 
02084   nsReconversionEvent reconversionEvent(PR_TRUE, NS_RECONVERSION_QUERY,
02085                                         focusedWidget);
02086   reconversionEvent.time = PR_IntervalNow();
02087 
02088   nsresult res = focusedWidget->DispatchWindowEvent(reconversionEvent);
02089 
02090   if (NS_SUCCEEDED(res)) {
02091      outString.Assign(reconversionEvent.theReply.mReconversionString);
02092      nsMemory::Free(reconversionEvent.theReply.mReconversionString);
02093   } 
02094   return res; 
02095   
02096 }
02097 //-------------------------------------------------------------------------
02098 //
02099 // HandleStartComposition
02100 //
02101 //-------------------------------------------------------------------------
02102 nsresult nsMacEventHandler::HandleStartComposition(void)
02103 {
02104 #ifdef DEBUG_TSM
02105        printf("HandleStartComposition\n");
02106 #endif
02107        mIMEIsComposing = PR_TRUE;
02108        if(nsnull == mIMECompositionStr)
02109               mIMECompositionStr = new nsAutoString();
02110        NS_ASSERTION(mIMECompositionStr, "cannot allocate mIMECompositionStr");
02111        if(nsnull == mIMECompositionStr)
02112        {
02113               return NS_ERROR_OUT_OF_MEMORY;
02114        }      
02115        // 
02116        // get the focused widget [tague: may need to rethink this later]
02117        //
02118        nsWindow* focusedWidget = mEventDispatchHandler->GetActive();
02119        if (!focusedWidget)
02120               focusedWidget = mTopLevelWidget;
02121        
02122        //
02123        // create the nsCompositionEvent
02124        //
02125        nsCompositionEvent compositionEvent(PR_TRUE, NS_COMPOSITION_START,
02126                                       focusedWidget);
02127        compositionEvent.time = PR_IntervalNow();
02128 
02129        nsresult res = focusedWidget->DispatchWindowEvent(compositionEvent);
02130        if(NS_SUCCEEDED(res)) {
02131               mIMEPos.x = compositionEvent.theReply.mCursorPosition.x;
02132               mIMEPos.y = compositionEvent.theReply.mCursorPosition.y
02133                         + compositionEvent.theReply.mCursorPosition.height;
02134               focusedWidget->LocalToWindowCoordinate(mIMEPos);
02135 #ifdef DEBUG_TSM
02136               printf("HandleStartComposition reply (%d,%d)\n", mIMEPos.x , mIMEPos.y);
02137 #endif
02138        }
02139        return res;
02140 }
02141 
02142 //-------------------------------------------------------------------------
02143 //
02144 // HandleEndComposition
02145 //
02146 //-------------------------------------------------------------------------
02147 nsresult nsMacEventHandler::HandleEndComposition(void)
02148 {
02149 #ifdef DEBUG_TSM
02150        printf("HandleEndComposition\n");
02151 #endif
02152        mIMEIsComposing = PR_FALSE;
02153        // 
02154        // get the focused widget [tague: may need to rethink this later]
02155        //
02156        nsWindow* focusedWidget = mEventDispatchHandler->GetActive();
02157        if (!focusedWidget)
02158               focusedWidget = mTopLevelWidget;
02159        
02160        //
02161        // create the nsCompositionEvent
02162        //
02163        nsCompositionEvent compositionEvent(PR_TRUE, NS_COMPOSITION_END,
02164                                       focusedWidget);
02165        compositionEvent.time = PR_IntervalNow();
02166 
02167        return(focusedWidget->DispatchWindowEvent(compositionEvent));
02168 }
02169 
02170 //-------------------------------------------------------------------------
02171 //
02172 // HandleTextEvent
02173 //
02174 //-------------------------------------------------------------------------
02175 nsresult nsMacEventHandler::HandleTextEvent(PRUint32 textRangeCount, nsTextRangeArray textRangeArray)
02176 {
02177 #ifdef DEBUG_TSM
02178        printf("HandleTextEvent\n");
02179        PRUint32 i;
02180        printf("text event \n[");
02181        const PRUnichar *ubuf = mIMECompositionStr->get();
02182        for(i=0; '\0' != *ubuf; i++)
02183               printf("U+%04X ", *ubuf++);
02184        printf("] len = %d\n",i);
02185        if(textRangeCount > 0)
02186        {
02187               for(i=0;i<textRangeCount;i++ )
02188               {
02189                      NS_ASSERTION((NS_TEXTRANGE_CARETPOSITION!=textRangeArray[i].mRangeType) ||
02190                                            (textRangeArray[i].mStartOffset == textRangeArray[i].mEndOffset),
02191                                            "start != end in CaretPosition");
02192                      NS_ASSERTION(
02193                             (NS_TEXTRANGE_CARETPOSITION==textRangeArray[i].mRangeType)||
02194                             (NS_TEXTRANGE_RAWINPUT==textRangeArray[i].mRangeType)||
02195                             (NS_TEXTRANGE_SELECTEDRAWTEXT==textRangeArray[i].mRangeType)||
02196                             (NS_TEXTRANGE_CONVERTEDTEXT==textRangeArray[i].mRangeType)||
02197                             (NS_TEXTRANGE_SELECTEDCONVERTEDTEXT==textRangeArray[i].mRangeType),
02198                             "illegal range type");
02199                      static char *name[6] =
02200                      {
02201                             "Unknown",
02202                             "CaretPosition", 
02203                             "RawInput", 
02204                             "SelectedRawText",
02205                             "ConvertedText",
02206                             "SelectedConvertedText"
02207                      };
02208                      printf("[%d,%d]=%s\n", 
02209                      textRangeArray[i].mStartOffset, 
02210                      textRangeArray[i].mEndOffset,
02211                      ((textRangeArray[i].mRangeType<=NS_TEXTRANGE_SELECTEDCONVERTEDTEXT) ?
02212                             name[textRangeArray[i].mRangeType] : name[0])
02213                      );
02214               }
02215        }
02216 #endif
02217        // 
02218        // get the focused widget [tague: may need to rethink this later]
02219        //
02220        nsWindow* focusedWidget = mEventDispatchHandler->GetActive();
02221        if (!focusedWidget)
02222               focusedWidget = mTopLevelWidget;
02223        
02224        //
02225        // create the nsTextEvent
02226        //
02227        nsTextEvent textEvent(PR_TRUE, NS_TEXT_TEXT, focusedWidget);
02228        textEvent.time = PR_IntervalNow();
02229        textEvent.theText = mIMECompositionStr->get();
02230        textEvent.rangeCount = textRangeCount;
02231        textEvent.rangeArray = textRangeArray;
02232 
02233        nsresult res = NS_OK;
02234        if (NS_SUCCEEDED(res = focusedWidget->DispatchWindowEvent(textEvent))) {
02235               mIMEPos.x = textEvent.theReply.mCursorPosition.x;
02236               mIMEPos.y = textEvent.theReply.mCursorPosition.y +
02237                           textEvent.theReply.mCursorPosition.height;
02238               mTopLevelWidget->LocalToWindowCoordinate(mIMEPos);
02239 #ifdef DEBUG_TSM
02240               printf("HandleTextEvent reply (%d,%d)\n", mIMEPos.x , mIMEPos.y);
02241 #endif
02242        } 
02243        return res;
02244 }
02245 nsresult nsMacEventHandler::ResetInputState()
02246 {
02247        OSErr err = noErr;
02248        if (mTSMDocument) {
02249               // make sure we do not use input widnow even some other code turn it for default by calling 
02250               // ::UseInputWindow(nsnull, TRUE); 
02251               ::UseInputWindow(mTSMDocument, FALSE); 
02252               err = ::FixTSMDocument(mTSMDocument);
02253               NS_ASSERTION( (noErr==err)||(tsmDocNotActiveErr==err)||(tsmTSNotOpenErr), "Cannot FixTSMDocument");
02254        }
02255        return NS_OK; 
02256 }
02257 
02258 PRBool
02259 nsMacEventHandler::HandleKeyUpDownEvent(EventHandlerCallRef aHandlerCallRef,
02260                                         EventRef aEvent)
02261 {
02262   ClearLastMouseUp();
02263 
02264   PRUint32 eventKind = ::GetEventKind(aEvent);
02265   NS_ASSERTION(eventKind == kEventRawKeyDown ||
02266                eventKind == kEventRawKeyUp,
02267                "Unknown event kind");
02268 
02269   OSStatus err = noErr;
02270 
02271   PRBool sendToTSM = PR_FALSE;
02272   if (eventKind == kEventRawKeyDown) {
02273     if (IsPluginFocused()) {
02274       if (mTSMDocument != ::TSMGetActiveDocument()) {
02275         // If some TSM document other than the one that we use for this window
02276         // is active, first try to call through to the TSM handler during a
02277         // keydown.  This can happen if a plugin installs its own TSM handler
02278         // and activates its own TSM document.
02279         // This is done early, before dispatching NS_KEY_DOWN because the
02280         // plugin will receive the keyDown event carried in the NS_KEY_DOWN.
02281         // If an IME session is active, this could cause the plugin to accept
02282         // both raw keydowns and text input from the IME session as input.
02283         err = ::CallNextEventHandler(aHandlerCallRef, aEvent);
02284         if (err == noErr) {
02285           // Someone other than us handled the event.  Don't send NS_KEY_DOWN.
02286           return PR_TRUE;
02287         }
02288 
02289         // No foreign handlers did anything.  Leave sendToTSM false so that
02290         // no subsequent attempts to call through to the foreign handler will
02291         // be made.
02292       }
02293       else {
02294         // The TSM document matches the one corresponding to the window.
02295         // An NS_KEY_DOWN event will be sent, and after that, it will be put
02296         // back into the handler chain to go to the TSM input handlers.
02297         // This assumes that the TSM handler is still ours, or that if
02298         // something else changed the TSM handler, that the new handler will
02299         // at least call through to ours.
02300         sendToTSM = PR_TRUE;
02301       }
02302     } else {
02303       // If the focus isn't currently in any plugin and we have a TSM document
02304       // that isn't currently active, activate it.  This helps with plugins
02305       // that set their own TSM document and then don't set it back, or don't
02306       // set it back correctly.  This should always have been the browser's
02307       // responsibility in any case.  This change resolves bmo bug 355071, and
02308       // also bmo bugs 345010 and (possibly) 318139 on the 1.8.1 branch.
02309       if (mTSMDocument && (mTSMDocument != ::TSMGetActiveDocument()))
02310         ::ActivateTSMDocument(mTSMDocument);
02311       sendToTSM = PR_TRUE;
02312     }
02313   }
02314 
02315   PRBool handled = PR_FALSE;
02316   nsWindow* focusedWidget = mEventDispatchHandler->GetActive();
02317   if (!focusedWidget)
02318     focusedWidget = mTopLevelWidget;
02319 
02320   PRUint32 modifiers = 0;
02321   err = ::GetEventParameter(aEvent, kEventParamKeyModifiers,
02322                             typeUInt32, NULL,
02323                             sizeof(modifiers), NULL,
02324                             &modifiers);
02325   NS_ASSERTION(err == noErr, "Could not get kEventParamKeyModifiers");
02326 
02327   PRUint32 keyCode = 0;
02328   err = ::GetEventParameter(aEvent, kEventParamKeyCode,
02329                             typeUInt32, NULL,
02330                             sizeof(keyCode), NULL,
02331                             &keyCode);
02332   NS_ASSERTION(err == noErr, "Could not get kEventParamKeyCode");
02333 
02334   PRUint8 charCode = 0;
02335   ::GetEventParameter(aEvent, kEventParamKeyMacCharCodes,
02336                       typeChar, NULL,
02337                       sizeof(charCode), NULL,
02338                       &charCode);
02339   // Failure is not a fatal condition.
02340 
02341   // The event's nativeMsg field historically held an EventRecord.  Some
02342   // consumers (plugins) rely on this behavior.  Note that
02343   // ConvertEventRefToEventRecord can return false and produce a null
02344   // event record in some cases, such as when entering an IME session.
02345   EventRecord eventRecord;
02346   ::ConvertEventRefToEventRecord(aEvent, &eventRecord);
02347 
02348   // kEventRawKeyDown or kEventRawKeyUp only
02349 
02350   PRUint32 message = (eventKind == kEventRawKeyUp ? NS_KEY_UP : NS_KEY_DOWN);
02351   nsKeyEvent upDownEvent(PR_TRUE, message, nsnull);
02352   upDownEvent.time =      PR_IntervalNow();
02353   upDownEvent.widget =    focusedWidget;
02354   upDownEvent.nativeMsg = (void*)&eventRecord;
02355   upDownEvent.isShift =   ((modifiers & shiftKey) != 0);
02356   upDownEvent.isControl = ((modifiers & controlKey) != 0);
02357   upDownEvent.isAlt =     ((modifiers & optionKey) != 0);
02358   upDownEvent.isMeta =    ((modifiers & cmdKey) != 0);
02359   upDownEvent.keyCode =   ConvertMacToRaptorKeyCode(charCode, keyCode,
02360                                                     modifiers);
02361   upDownEvent.charCode =  0;
02362   handled = focusedWidget->DispatchWindowEvent(upDownEvent);
02363 
02364   if (eventKind == kEventRawKeyUp)
02365     return handled;
02366 
02367   // kEventRawKeyDown only.  Prepare for a possible NS_KEY_PRESS event.
02368 
02369   nsWindow* checkFocusedWidget = mEventDispatchHandler->GetActive();
02370   if (!checkFocusedWidget)
02371     checkFocusedWidget = mTopLevelWidget;
02372 
02373   // Set a flag indicating that NS_KEY_PRESS events should not be dispatched,
02374   // because focus changed.
02375   PRBool lastIgnore = PR_FALSE;
02376   if (checkFocusedWidget != focusedWidget) {
02377     lastIgnore = mKeyIgnore;
02378     mKeyIgnore = PR_TRUE;
02379   }
02380 
02381   // Set a flag indicating that the NS_KEY_DOWN event came back with
02382   // preventDefault, and NS_KEY_PRESS events should have the same flag set.
02383   PRBool lastHandled = PR_FALSE;
02384   if (handled) {
02385     lastHandled = mKeyHandled;
02386     mKeyHandled = PR_TRUE;
02387   }
02388 
02389   if (sendToTSM) {
02390     // The event needs further processing.
02391     //  - If no input method is active, an event will be delivered to the
02392     //    kEventTextInputUnicodeForKeyEvent handler, which will call
02393     //    HandleUKeyEvent, which takes care of dispatching NS_KEY_PRESS events.
02394     //  - If an input method is active, an event will be delivered to the
02395     //    kEventTextInputUpdateActiveInputArea handler, which will call
02396     //    UnicodeHandleUpdateInputArea to handle the input session.
02397     ::CallNextEventHandler(aHandlerCallRef, aEvent);
02398   }
02399 
02400   mKeyHandled = lastHandled;
02401   mKeyIgnore = lastIgnore;
02402 
02403   return handled;
02404 }
02405 
02406 PRBool
02407 nsMacEventHandler::HandleKeyModifierEvent(EventHandlerCallRef aHandlerCallRef,
02408                                           EventRef aEvent)
02409 {
02410   ClearLastMouseUp();
02411 
02412   PRBool handled = PR_FALSE;
02413   nsWindow* focusedWidget = mEventDispatchHandler->GetActive();
02414   if (!focusedWidget)
02415     focusedWidget = mTopLevelWidget;
02416 
02417   PRUint32 modifiers = 0;
02418   OSStatus err = ::GetEventParameter(aEvent, kEventParamKeyModifiers,
02419                                      typeUInt32, NULL,
02420                                      sizeof(modifiers), NULL,
02421                                      &modifiers);
02422   NS_ASSERTION(err == noErr, "Could not get kEventParamKeyModifiers");
02423 
02424   typedef struct {
02425     PRUint32 modifierBit;
02426     PRUint32 keycode;
02427   } ModifierToKeycode;
02428   const ModifierToKeycode kModifierToKeycodeTable[] = {
02429     { shiftKey,   NS_VK_SHIFT },
02430     { controlKey, NS_VK_CONTROL },
02431     { optionKey,  NS_VK_ALT },
02432     { cmdKey,     NS_VK_META },
02433   };
02434   const PRUint32 kModifierCount = sizeof(kModifierToKeycodeTable) /
02435                                   sizeof(ModifierToKeycode);
02436 
02437   // This will be a null event, but include it anyway because it'll still have
02438   // good when, where, and modifiers fields, and because it's present in other
02439   // NS_KEY_DOWN and NS_KEY_UP events.
02440   EventRecord eventRecord;
02441   ::ConvertEventRefToEventRecord(aEvent, &eventRecord);
02442 
02443   for(PRUint32 i = 0 ; i < kModifierCount ; i++) {
02444     PRUint32 modifierBit = kModifierToKeycodeTable[i].modifierBit;
02445     if ((modifiers & modifierBit) != (mLastModifierState & modifierBit)) {
02446       PRUint32 message = ((modifiers & modifierBit) != 0 ? NS_KEY_DOWN :
02447                                                            NS_KEY_UP);
02448       nsKeyEvent upDownEvent(PR_TRUE, message, nsnull);
02449       upDownEvent.time =      PR_IntervalNow();
02450       upDownEvent.widget =    focusedWidget;
02451       upDownEvent.nativeMsg = (void*)&eventRecord;
02452       upDownEvent.isShift =   ((modifiers & shiftKey) != 0);
02453       upDownEvent.isControl = ((modifiers & controlKey) != 0);
02454       upDownEvent.isAlt =     ((modifiers & optionKey) != 0);
02455       upDownEvent.isMeta =    ((modifiers & cmdKey) != 0);
02456       upDownEvent.keyCode =   kModifierToKeycodeTable[i].keycode;
02457       upDownEvent.charCode =  0;
02458       handled |= focusedWidget->DispatchWindowEvent(upDownEvent);
02459 
02460       // No need to preventDefault additional events.  Although
02461       // kEventRawKeyModifiersChanged can carry multiple modifiers going
02462       // up or down, Gecko treats them independently.
02463  
02464       // Stop if focus has changed.
02465       nsWindow* checkFocusedWidget = mEventDispatchHandler->GetActive();
02466       if (!checkFocusedWidget)
02467         checkFocusedWidget = mTopLevelWidget;
02468 
02469       if (checkFocusedWidget != focusedWidget)
02470         break;
02471     }
02472   }
02473 
02474   mLastModifierState = modifiers;
02475   return handled;
02476 }
02477 
02478 void
02479 nsMacEventHandler::ClearLastMouseUp()
02480 {
02481   mLastMouseUpWhere.h = 0;
02482   mLastMouseUpWhere.v = 0;
02483   mLastMouseUpWhen = 0;
02484   mClickCount = 0;
02485 }
02486 
02487 // Returns NS_TRUE if a plugin is currently focused, otherwise returns
02488 // NS_FALSE.
02489 PRBool
02490 nsMacEventHandler::IsPluginFocused()
02491 {
02492   PRBool retval = PR_FALSE;
02493   nsIWidget* widget = mEventDispatchHandler->GetActive();
02494   nsIDocument *doc = nsToolkit::GetDocumentFor(widget);
02495   if (doc) {
02496     nsIPresShell* presShell = doc->GetShellAt(0);
02497     nsIEventStateManager* esm = presShell->GetPresContext()->EventStateManager();
02498     nsIFrame *focusedFrame = nsnull;
02499     esm->GetFocusedFrame(&focusedFrame);
02500     if (focusedFrame) {
02501       nsIObjectFrame *pluginFrame;
02502       // There's no need to call Release() on objectIFrame, since AddRef()
02503       // and Release() don't work on frames.
02504       if (NS_SUCCEEDED(CallQueryInterface(focusedFrame, &pluginFrame)))
02505         retval = PR_TRUE;
02506     }
02507   }
02508   return retval;
02509 }
02510 
02511 void
02512 nsMacEventHandler::ClearWindowRefs(nsWindow* aWindow)
02513 {
02514   if (sLastActive && sLastActive->mTopLevelWidget == aWindow) {
02515     sLastActive = nsnull;
02516   }
02517 }
02518