Mozilla/mozilla/widget/src/mac/nsMacEventHandler.cpp
pierre%netscape.com 6d043a28a5 Fixed a crash in HandleMenuCommand(). It could especially happen on Quit.
git-svn-id: svn://10.0.0.236/trunk@35706 18797224-902f-48f8-a5cc-f745e15eee43
1999-06-16 06:22:11 +00:00

1290 lines
38 KiB
C++
Raw Blame History

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsMacEventHandler.h"
#include "nsWindow.h"
#include "nsMacWindow.h"
#include "nsToolkit.h"
#include "prinrval.h"
#include <ToolUtils.h>
#include <DiskInit.h>
#include <LowMem.h>
#include <TextServices.h>
#include <UnicodeConverter.h>
#include <Script.h>
// from MacHeaders.c
#ifndef topLeft
#define topLeft(r) (((Point *) &(r))[0])
#endif
#ifndef botRight
#define botRight(r) (((Point *) &(r))[1])
#endif
PRBool nsMacEventHandler::mInBackground = PR_FALSE;
//-------------------------------------------------------------------------
//
// nsMacEventHandler constructor/destructor
//
//-------------------------------------------------------------------------
nsMacEventHandler::nsMacEventHandler(nsMacWindow* aTopLevelWidget)
{
OSErr err;
InterfaceTypeList supportedServices;
mTopLevelWidget = aTopLevelWidget;
mLastWidgetHit = nsnull;
mLastWidgetPointed = nsnull;
//
// create a TSMDocument for this window. We are allocating a TSM document for
// each Mac window
//
supportedServices[0] = kTextService;
err = ::NewTSMDocument(1,supportedServices,&mTSMDocument,(long)this);
NS_ASSERTION(err==noErr,"nsMacEventHandler::nsMacEventHandler: NewTSMDocument failed.");
printf("nsMacEventHandler::nsMacEventHandler: created TSMDocument[%p]\n",mTSMDocument);
mIMEIsComposing = PR_FALSE;
mIMECompositionString = nsnull;
mIMECompositionStringSize = 0;
mIMECompositionStringLength = 0;
}
nsMacEventHandler::~nsMacEventHandler()
{
if (mLastWidgetPointed)
mLastWidgetPointed->RemoveDeleteObserver(this);
if (mLastWidgetHit)
mLastWidgetHit->RemoveDeleteObserver(this);
if (mTSMDocument)
(void)::DeleteTSMDocument(mTSMDocument);
}
void nsMacEventHandler::NotifyDelete(void* aDeletedObject)
{
if (mLastWidgetPointed == aDeletedObject)
mLastWidgetPointed = nsnull;
if (mLastWidgetHit == aDeletedObject)
mLastWidgetHit = nsnull;
}
#pragma mark -
//-------------------------------------------------------------------------
//
// HandleOSEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleOSEvent ( EventRecord& aOSEvent )
{
PRBool retVal = PR_FALSE;
switch (aOSEvent.what)
{
case keyUp:
case keyDown:
case autoKey:
retVal = HandleKeyEvent(aOSEvent);
break;
case activateEvt:
retVal = HandleActivateEvent(aOSEvent);
break;
case updateEvt:
retVal = HandleUpdateEvent(aOSEvent);
break;
case mouseDown:
retVal = HandleMouseDownEvent(aOSEvent);
break;
case mouseUp:
retVal = HandleMouseUpEvent(aOSEvent);
break;
case osEvt:
unsigned char eventType = ((aOSEvent.message >> 24) & 0x00ff);
if (eventType == suspendResumeMessage)
{
if ((aOSEvent.message & 1) == resumeFlag)
mInBackground = PR_FALSE; // resume message
else
mInBackground = PR_TRUE; // suspend message
}
else {
if (! mInBackground)
retVal = HandleMouseMoveEvent(aOSEvent);
}
break;
case nullEvent:
if (! mInBackground)
retVal = HandleMouseMoveEvent(aOSEvent);
break;
}
return retVal;
}
//-------------------------------------------------------------------------
//
// Handle Menu commands
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleMenuCommand(
EventRecord& aOSEvent,
long aMenuResult)
{
// get the focused widget
nsWindow* focusedWidget = mTopLevelWidget;
nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)mTopLevelWidget->GetToolkit()) );
if (toolkit)
focusedWidget = toolkit->GetFocus();
if (!focusedWidget)
return PR_FALSE;
// nsEvent
nsMenuEvent menuEvent;
menuEvent.eventStructType = NS_MENU_EVENT;
menuEvent.message = NS_MENU_SELECTED;
menuEvent.point.x = aOSEvent.where.h;
menuEvent.point.y = aOSEvent.where.v;
menuEvent.time = PR_IntervalNow();
// nsGUIEvent
menuEvent.widget = focusedWidget;
menuEvent.nativeMsg = (void*)&aOSEvent;
// nsMenuEvent
menuEvent.mMenuItem = nsnull; //<2F>TODO: initialize mMenuItem
menuEvent.mCommand = aMenuResult;
// dispatch the menu event: if it is not processed by the focused widget,
// propagate the event through the different parents all the way up to the window
PRBool eventHandled = focusedWidget->DispatchWindowEvent(menuEvent);
if (! eventHandled)
{
nsCOMPtr<nsWindow> grandParent;
nsCOMPtr<nsWindow> parent ( dont_AddRef((nsWindow*)focusedWidget->GetParent()) );
while (parent)
{
menuEvent.widget = parent;
eventHandled = parent->DispatchWindowEvent(menuEvent);
if (eventHandled)
{
break;
}
else
{
grandParent = dont_AddRef((nsWindow*)parent->GetParent());
parent = grandParent;
}
}
}
return eventHandled;
}
//-------------------------------------------------------------------------
//
// DragEvent
//
//-------------------------------------------------------------------------
//
// Someone on the outside told us that something related to a drag is happening. The
// exact event type is passed in as |aMessage|. We need to send this event into Gecko
// for processing. Create a Gecko event (using the appropriate message type) and pass
// it along.
//
// <20><><EFBFBD>THIS REALLY NEEDS TO BE CLEANED UP! TOO MUCH CODE COPIED FROM ConvertOSEventToMouseEvent
//
PRBool nsMacEventHandler::DragEvent ( unsigned int aMessage, Point aMouseGlobal, UInt16 aKeyModifiers )
{
printf("dispatching event %ld into Gecko\n", aMessage);
nsMouseEvent geckoEvent;
// convert the mouse to local coordinates. We have to do all the funny port origin
// stuff just in case it has been changed.
Point hitPointLocal = aMouseGlobal;
#if TARGET_CARBON
GrafPtr grafPort = reinterpret_cast<GrafPtr>(mTopLevelWidget->GetNativeData(NS_NATIVE_GRAPHIC));
::SetPort(grafPort);
Rect savePortRect;
::GetPortBounds(grafPort, &savePortRect);
#else
GrafPtr grafPort = static_cast<GrafPort*>(mTopLevelWidget->GetNativeData(NS_NATIVE_GRAPHIC));
::SetPort(grafPort);
Rect savePortRect = grafPort->portRect;
#endif
::SetOrigin(0, 0);
::GlobalToLocal(&hitPointLocal);
::SetOrigin(savePortRect.left, savePortRect.top);
nsPoint widgetHitPoint(hitPointLocal.h, hitPointLocal.v);
nsWindow* widgetHit = mTopLevelWidget->FindWidgetHit(hitPointLocal);
if ( widgetHit ) {
// adjust from local coordinates to window coordinates in case the top level widget
// isn't at 0, 0
nsRect bounds;
mTopLevelWidget->GetBounds(bounds);
nsPoint widgetOrigin(bounds.x, bounds.y);
widgetHit->LocalToWindowCoordinate(widgetOrigin);
widgetHitPoint.MoveBy(-widgetOrigin.x, -widgetOrigin.y);
}
else
widgetHit = mTopLevelWidget;
// nsEvent
geckoEvent.eventStructType = NS_DRAGDROP_EVENT;
geckoEvent.message = aMessage;
geckoEvent.point = widgetHitPoint;
geckoEvent.time = PR_IntervalNow();
// nsGUIEvent
geckoEvent.widget = widgetHit;
geckoEvent.nativeMsg = nsnull;
// nsInputEvent
geckoEvent.isShift = ((aKeyModifiers & shiftKey) != 0);
geckoEvent.isControl = ((aKeyModifiers & controlKey) != 0);
geckoEvent.isAlt = ((aKeyModifiers & optionKey) != 0);
geckoEvent.isCommand = ((aKeyModifiers & cmdKey) != 0);
// nsMouseEvent
geckoEvent.clickCount = 1;
widgetHit->DispatchMouseEvent(geckoEvent);
return PR_TRUE;
} // DropOccurred
#pragma mark -
//-------------------------------------------------------------------------
//
// ConvertMacToRaptorKeyCode
//
//-------------------------------------------------------------------------
// Key code constants
enum
{
kEscapeKeyCode = 0x35,
kShiftKeyCode = 0x38,
kCapsLockKeyCode = 0x39,
kControlKeyCode = 0x3B,
kOptionkeyCode = 0x3A, // left and right option keys
kClearKeyCode = 0x47,
// function keys
kF1KeyCode = 0x7A,
kF2KeyCode = 0x78,
kF3KeyCode = 0x63,
kF4KeyCode = 0x76,
kF5KeyCode = 0x60,
kF6KeyCode = 0x61,
kF7KeyCode = 0x62,
kF8KeyCode = 0x64,
kF9KeyCode = 0x65,
kF10KeyCode = 0x6D,
kF11KeyCode = 0x67,
kF12KeyCode = 0x6F,
kF13KeyCode = 0x69,
kF14KeyCode = 0x6B,
kF15KeyCode = 0x71,
kPrintScreenKeyCode = kF13KeyCode,
kScrollLockKeyCode = kF14KeyCode,
kPauseKeyCode = kF15KeyCode,
// keypad
kKeypad0KeyCode = 0x52,
kKeypad1KeyCode = 0x53,
kKeypad2KeyCode = 0x54,
kKeypad3KeyCode = 0x55,
kKeypad4KeyCode = 0x56,
kKeypad5KeyCode = 0x57,
kKeypad6KeyCode = 0x58,
kKeypad7KeyCode = 0x59,
kKeypad8KeyCode = 0x5B,
kKeypad9KeyCode = 0x5C,
kKeypadMultiplyKeyCode = 0x43,
kKeypadAddKeyCode = 0x45,
kKeypadSubtractKeyCode = 0x4E,
kKeypadDecimalKeyCode = 0x41,
kKeypadDivideKeyCode = 0x4B,
kKeypadEqualsKeyCode = 0x51, // no correpsonding raptor key code
kInsertKeyCode = 0x72, // also help key
kDeleteKeyCode = 0x75, // also forward delete key
kTabKeyCode = 0x30,
kHomeKeyCode = 0x73,
kEndKeyCode = 0x77,
kPageUpKeyCode = 0x74,
kPageDownKeyCode = 0x79,
kLeftArrowKeyCode = 0x7B,
kRightArrowKeyCode = 0x7C,
kUpArrowKeyCode = 0x7E,
kDownArrowKeyCode = 0x7D
};
static PRUint32 ConvertMacToRaptorKeyCode(UInt32 eventMessage, UInt32 eventModifiers)
{
UInt8 charCode = (eventMessage & charCodeMask);
UInt8 keyCode = (eventMessage & keyCodeMask) >> 8;
PRUint32 raptorKeyCode = 0;
switch (keyCode)
{
// case ?? : raptorKeyCode = NS_VK_CANCEL; break; // don't know what this key means. Nor does joki
// modifiers. We don't get separate events for these
case kEscapeKeyCode: raptorKeyCode = NS_VK_ESCAPE; break;
case kShiftKeyCode: raptorKeyCode = NS_VK_SHIFT; break;
case kCapsLockKeyCode: raptorKeyCode = NS_VK_CAPS_LOCK; break;
case kControlKeyCode: raptorKeyCode = NS_VK_CONTROL; break;
case kOptionkeyCode: raptorKeyCode = NS_VK_ALT; break;
case kClearKeyCode: raptorKeyCode = NS_VK_CLEAR; break;
// function keys
case kF1KeyCode: raptorKeyCode = NS_VK_F1; break;
case kF2KeyCode: raptorKeyCode = NS_VK_F2; break;
case kF3KeyCode: raptorKeyCode = NS_VK_F3; break;
case kF4KeyCode: raptorKeyCode = NS_VK_F4; break;
case kF5KeyCode: raptorKeyCode = NS_VK_F5; break;
case kF6KeyCode: raptorKeyCode = NS_VK_F6; break;
case kF7KeyCode: raptorKeyCode = NS_VK_F7; break;
case kF8KeyCode: raptorKeyCode = NS_VK_F8; break;
case kF9KeyCode: raptorKeyCode = NS_VK_F9; break;
case kF10KeyCode: raptorKeyCode = NS_VK_F10; break;
case kF11KeyCode: raptorKeyCode = NS_VK_F11; break;
case kF12KeyCode: raptorKeyCode = NS_VK_F12; break;
// case kF13KeyCode: raptorKeyCode = NS_VK_F13; break; // clash with the 3 below
// case kF14KeyCode: raptorKeyCode = NS_VK_F14; break;
// case kF15KeyCode: raptorKeyCode = NS_VK_F15; break;
case kPauseKeyCode: raptorKeyCode = NS_VK_PAUSE; break;
case kScrollLockKeyCode: raptorKeyCode = NS_VK_SCROLL_LOCK; break;
case kPrintScreenKeyCode: raptorKeyCode = NS_VK_PRINTSCREEN; break;
// keypad
case kKeypad0KeyCode: raptorKeyCode = NS_VK_NUMPAD0; break;
case kKeypad1KeyCode: raptorKeyCode = NS_VK_NUMPAD1; break;
case kKeypad2KeyCode: raptorKeyCode = NS_VK_NUMPAD2; break;
case kKeypad3KeyCode: raptorKeyCode = NS_VK_NUMPAD3; break;
case kKeypad4KeyCode: raptorKeyCode = NS_VK_NUMPAD4; break;
case kKeypad5KeyCode: raptorKeyCode = NS_VK_NUMPAD5; break;
case kKeypad6KeyCode: raptorKeyCode = NS_VK_NUMPAD6; break;
case kKeypad7KeyCode: raptorKeyCode = NS_VK_NUMPAD7; break;
case kKeypad8KeyCode: raptorKeyCode = NS_VK_NUMPAD8; break;
case kKeypad9KeyCode: raptorKeyCode = NS_VK_NUMPAD9; break;
case kKeypadMultiplyKeyCode: raptorKeyCode = NS_VK_MULTIPLY; break;
case kKeypadAddKeyCode: raptorKeyCode = NS_VK_ADD; break;
case kKeypadSubtractKeyCode: raptorKeyCode = NS_VK_SUBTRACT; break;
case kKeypadDecimalKeyCode: raptorKeyCode = NS_VK_DECIMAL; break;
case kKeypadDivideKeyCode: raptorKeyCode = NS_VK_DIVIDE; break;
// case ?? : raptorKeyCode = NS_VK_SEPARATOR; break;
// these may clash with forward delete and help
// case kInsertKeyCode: raptorKeyCode = NS_VK_INSERT; break;
// case kDeleteKeyCode: raptorKeyCode = NS_VK_DELETE; break;
default:
// if we haven't gotten the key code already, look at the char code
switch (charCode)
{
case kReturnCharCode: raptorKeyCode = NS_VK_RETURN; break;
case kEnterCharCode: raptorKeyCode = NS_VK_RETURN; break; // fix me!
case kBackspaceCharCode: raptorKeyCode = NS_VK_BACK; break;
case kDeleteCharCode: raptorKeyCode = NS_VK_DELETE; break;
case kTabCharCode: raptorKeyCode = NS_VK_TAB; break;
case kHomeCharCode: raptorKeyCode = NS_VK_HOME; break;
case kEndCharCode: raptorKeyCode = NS_VK_END; break;
case kPageUpCharCode: raptorKeyCode = NS_VK_PAGE_UP; break;
case kPageDownCharCode: raptorKeyCode = NS_VK_PAGE_DOWN; break;
case kLeftArrowCharCode: raptorKeyCode = NS_VK_LEFT; break;
case kRightArrowCharCode: raptorKeyCode = NS_VK_RIGHT; break;
case kUpArrowCharCode: raptorKeyCode = NS_VK_UP; break;
case kDownArrowCharCode: raptorKeyCode = NS_VK_DOWN; break;
case ' ': raptorKeyCode = NS_VK_SPACE; break;
case ';': raptorKeyCode = NS_VK_SEMICOLON; break;
case '=': raptorKeyCode = NS_VK_EQUALS; break;
case ',': raptorKeyCode = NS_VK_COMMA; break;
case '.': raptorKeyCode = NS_VK_PERIOD; break;
case '/': raptorKeyCode = NS_VK_SLASH; break;
case '`': raptorKeyCode = NS_VK_BACK_QUOTE; break;
case '{':
case '[': raptorKeyCode = NS_VK_OPEN_BRACKET; break;
case '\\': raptorKeyCode = NS_VK_BACK_SLASH; break;
case '}':
case ']': raptorKeyCode = NS_VK_CLOSE_BRACKET; break;
case '\'':
case '"': raptorKeyCode = NS_VK_QUOTE; break;
default:
if (charCode >= '0' && charCode <= '9') // numerals
{
raptorKeyCode = charCode;
}
else if (charCode >= 'a' && charCode <= 'z') // lowercase
{
raptorKeyCode = toupper(charCode);
}
else if (charCode >= 'A' && charCode <= 'Z') // uppercase
{
raptorKeyCode = charCode;
}
break;
}
}
return raptorKeyCode;
}
//-------------------------------------------------------------------------
//
// InitializeKeyEvent
//
//-------------------------------------------------------------------------
void nsMacEventHandler::InitializeKeyEvent(nsKeyEvent& aKeyEvent, EventRecord& aOSEvent, nsWindow* focusedWidget, PRUint32 message)
{
//
// initalize the basic message parts
//
aKeyEvent.eventStructType = NS_KEY_EVENT;
aKeyEvent.message = message;
aKeyEvent.point.x = 0;
aKeyEvent.point.y = 0;
aKeyEvent.time = PR_IntervalNow();
//
// initalize the GUI event parts
//
aKeyEvent.widget = focusedWidget;
aKeyEvent.nativeMsg = (void*)&aOSEvent;
//
// nsInputEvent parts
//
aKeyEvent.isShift = ((aOSEvent.modifiers & shiftKey) != 0);
aKeyEvent.isControl = ((aOSEvent.modifiers & controlKey) != 0);
aKeyEvent.isAlt = ((aOSEvent.modifiers & optionKey) != 0);
aKeyEvent.isCommand = ((aOSEvent.modifiers & cmdKey) != 0);
//
// nsKeyEvent parts
//
aKeyEvent.keyCode = ConvertMacToRaptorKeyCode(aOSEvent.message, aOSEvent.modifiers);
aKeyEvent.charCode = aOSEvent.message & charCodeMask; // will be translated to Unicode, see ConvertKeyEventToUnicode
}
//-------------------------------------------------------------------------
//
// IsSpecialRaptorKey
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::IsSpecialRaptorKey(UInt32 macKeyCode)
{
PRBool isSpecial;
//
// this table is used to make the macintosh virtual key generation behave the same
// as windows and linux
//
switch (macKeyCode)
{
// modifiers. We don't get separate events for these
case kEscapeKeyCode: isSpecial = PR_TRUE; break;
case kShiftKeyCode: isSpecial = PR_TRUE; break;
case kCapsLockKeyCode: isSpecial = PR_TRUE; break;
case kControlKeyCode: isSpecial = PR_TRUE; break;
case kOptionkeyCode: isSpecial = PR_TRUE; break;
case kClearKeyCode: isSpecial = PR_TRUE; break;
// function keys
case kF1KeyCode: isSpecial = PR_TRUE; break;
case kF2KeyCode: isSpecial = PR_TRUE; break;
case kF3KeyCode: isSpecial = PR_TRUE; break;
case kF4KeyCode: isSpecial = PR_TRUE; break;
case kF5KeyCode: isSpecial = PR_TRUE; break;
case kF6KeyCode: isSpecial = PR_TRUE; break;
case kF7KeyCode: isSpecial = PR_TRUE; break;
case kF8KeyCode: isSpecial = PR_TRUE; break;
case kF9KeyCode: isSpecial = PR_TRUE; break;
case kF10KeyCode: isSpecial = PR_TRUE; break;
case kF11KeyCode: isSpecial = PR_TRUE; break;
case kF12KeyCode: isSpecial = PR_TRUE; break;
case kPauseKeyCode: isSpecial = PR_TRUE; break;
case kScrollLockKeyCode: isSpecial = PR_TRUE; break;
case kPrintScreenKeyCode: isSpecial = PR_TRUE; break;
// keypad
case kKeypad0KeyCode: isSpecial = PR_TRUE; break;
case kKeypad1KeyCode: isSpecial = PR_TRUE; break;
case kKeypad2KeyCode: isSpecial = PR_TRUE; break;
case kKeypad3KeyCode: isSpecial = PR_TRUE; break;
case kKeypad4KeyCode: isSpecial = PR_TRUE; break;
case kKeypad5KeyCode: isSpecial = PR_TRUE; break;
case kKeypad6KeyCode: isSpecial = PR_TRUE; break;
case kKeypad7KeyCode: isSpecial = PR_TRUE; break;
case kKeypad8KeyCode: isSpecial = PR_TRUE; break;
case kKeypad9KeyCode: isSpecial = PR_TRUE; break;
case kKeypadMultiplyKeyCode: isSpecial = PR_TRUE; break;
case kKeypadAddKeyCode: isSpecial = PR_TRUE; break;
case kKeypadSubtractKeyCode: isSpecial = PR_TRUE; break;
case kKeypadDecimalKeyCode: isSpecial = PR_TRUE; break;
case kKeypadDivideKeyCode: isSpecial = PR_TRUE; break;
case kDeleteKeyCode: isSpecial = PR_TRUE; break;
case kTabKeyCode: isSpecial = PR_TRUE; break;
case kHomeKeyCode: isSpecial = PR_TRUE; break;
case kEndKeyCode: isSpecial = PR_TRUE; break;
case kPageUpKeyCode: isSpecial = PR_TRUE; break;
case kPageDownKeyCode: isSpecial = PR_TRUE; break;
case kLeftArrowKeyCode: isSpecial = PR_TRUE; break;
case kRightArrowKeyCode: isSpecial = PR_TRUE; break;
case kUpArrowKeyCode: isSpecial = PR_TRUE; break;
case kDownArrowKeyCode: isSpecial = PR_TRUE; break;
default: isSpecial = PR_FALSE; break;
}
return isSpecial;
}
//-------------------------------------------------------------------------
//
// ConvertKeyEventToUnicode
//
//-------------------------------------------------------------------------
void nsMacEventHandler::ConvertKeyEventToUnicode(nsKeyEvent& aKeyEvent, EventRecord& aOSEvent)
{
aKeyEvent.charCode = 0;
char charResult = aOSEvent.message & charCodeMask;
//
// get the script of text for Unicode conversion
//
ScriptCode textScript = (ScriptCode)GetScriptManagerVariable(smKeyScript);
//
// convert our script code (smKeyScript) to a TextEncoding
//
TextEncoding textEncodingFromScript;
OSErr err = ::UpgradeScriptInfoToTextEncoding(textScript, kTextLanguageDontCare, kTextRegionDontCare, nsnull,
&textEncodingFromScript);
NS_ASSERTION(err == noErr, "nsMacEventHandler::ConvertKeyEventToUnicode: UpgradeScriptInfoToTextEncoding failed.");
if (err != noErr) return;
TextToUnicodeInfo textToUnicodeInfo;
err = ::CreateTextToUnicodeInfoByEncoding(textEncodingFromScript,&textToUnicodeInfo);
NS_ASSERTION(err == noErr, "nsMacEventHandler::ConvertKeyEventToUnicode: CreateUnicodeToTextInfoByEncoding failed.");
if (err != noErr) return;
//
// convert to Unicode
//
ByteCount result_size, source_read;
PRUnichar unicharResult;
err = ::ConvertFromTextToUnicode(textToUnicodeInfo,
sizeof(char),&charResult,
kUnicodeLooseMappingsMask,
0,NULL,NULL,NULL,
sizeof(PRUnichar),&source_read,
&result_size,&unicharResult);
::DisposeTextToUnicodeInfo(&textToUnicodeInfo);
NS_ASSERTION(err == noErr, "nsMacEventHandler::ConvertKeyEventToUnicode: ConverFromTextToUnicode failed.");
if (err != noErr) return;
aKeyEvent.charCode = unicharResult;
}
//-------------------------------------------------------------------------
//
// HandleKeyEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleKeyEvent(EventRecord& aOSEvent)
{
nsresult result;
// get the focused widget
nsWindow* focusedWidget = mTopLevelWidget;
nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)mTopLevelWidget->GetToolkit()) );
if (toolkit)
focusedWidget = toolkit->GetFocus();
if (!focusedWidget)
return PR_FALSE;
// nsEvent
nsKeyEvent keyEvent;
switch (aOSEvent.what)
{
case keyUp:
InitializeKeyEvent(keyEvent,aOSEvent,focusedWidget,NS_KEY_UP);
result = focusedWidget->DispatchWindowEvent(keyEvent);
break;
case keyDown:
case autoKey:
InitializeKeyEvent(keyEvent,aOSEvent,focusedWidget,NS_KEY_DOWN);
result = focusedWidget->DispatchWindowEvent(keyEvent);
if (! IsSpecialRaptorKey((aOSEvent.message & keyCodeMask) >> 8))
{
InitializeKeyEvent(keyEvent,aOSEvent,focusedWidget,NS_KEY_PRESS);
ConvertKeyEventToUnicode(keyEvent,aOSEvent);
result = focusedWidget->DispatchWindowEvent(keyEvent);
}
break;
}
return result;
}
#pragma mark -
//-------------------------------------------------------------------------
//
// HandleActivateEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleActivateEvent(EventRecord& aOSEvent)
{
OSErr err;
nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)mTopLevelWidget->GetToolkit()) );
if (toolkit)
{
Boolean isActive = ((aOSEvent.modifiers & activeFlag) != 0);
if (isActive)
{
//
// Activate The TSMDocument associated with this handler
//
err = ::ActivateTSMDocument(mTSMDocument);
#if 0
NS_ASSERTION(err==noErr,"nsMacEventHandler::HandleActivateEvent: ActivateTSMDocument failed");
#endif
printf("nsEventHandler::HandleActivateEvent: ActivateTSMDocument[%p]\n",mTSMDocument);
//<2F>TODO: retrieve the focused widget for that window
nsWindow* focusedWidget = mTopLevelWidget;
toolkit->SetFocus(focusedWidget);
nsIMenuBar* menuBar = focusedWidget->GetMenuBar();
if (menuBar)
{
MenuHandle menuHandle = nsnull;
menuBar->GetNativeData((void *)menuHandle);
::SetMenuBar((Handle)menuHandle);
menuBar->Paint();
}
else
{
//<2F>TODO: if the focusedWidget doesn't have a menubar,
// look all the way up to the window
// until one of the parents has a menubar
}
//<2F>TODO: set the menu bar here
}
else
{
//
// Deactivate the TSMDocument assoicated with this EventHandler
//
err = ::DeactivateTSMDocument(mTSMDocument);
#if 0
NS_ASSERTION(err==noErr,"nsMacEventHandler::HandleActivateEvent: DeactivateTSMDocument failed");
#endif
printf("nsEventHandler::HandleActivateEvent: DeactivateTSMDocument[%p]\n",mTSMDocument);
//<2F>TODO: save the focused widget for that window
toolkit->SetFocus(nsnull);
nsIMenuBar* menuBarInterface = mTopLevelWidget->GetMenuBar();
if (menuBarInterface)
{
Handle menuBar = ::GetMenuBar(); // Get a copy of the menu list
menuBarInterface->SetNativeData((void*)menuBar);
}
}
}
return PR_TRUE;
}
//-------------------------------------------------------------------------
//
// HandleUpdateEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleUpdateEvent(EventRecord& aOSEvent)
{
mTopLevelWidget->HandleUpdateEvent();
return PR_TRUE;
}
//-------------------------------------------------------------------------
//
// HandleMouseDownEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleMouseDownEvent(
EventRecord& aOSEvent)
{
PRBool retVal = PR_FALSE;
WindowPtr whichWindow;
short partCode = ::FindWindow(aOSEvent.where, &whichWindow);
switch (partCode)
{
case inDrag:
{
Point macPoint;
#if TARGET_CARBON
Rect portRect;
::GetPortBounds(GetWindowPort(whichWindow), &portRect);
macPoint = topLeft(portRect);
#else
macPoint = topLeft(whichWindow->portRect);
#endif
::LocalToGlobal(&macPoint);
mTopLevelWidget->Move(macPoint.h, macPoint.v);
break;
}
case inGrow:
{
#if TARGET_CARBON
Rect macRect;
::GetWindowPortBounds ( whichWindow, &macRect );
#else
Rect macRect = whichWindow->portRect;
#endif
::LocalToGlobal(&topLeft(macRect));
::LocalToGlobal(&botRight(macRect));
mTopLevelWidget->Resize(macRect.right - macRect.left + 1, macRect.bottom - macRect.top + 1, PR_FALSE);
break;
}
case inGoAway:
{
mTopLevelWidget->Destroy();
break;
}
case inContent:
{
nsMouseEvent mouseEvent;
ConvertOSEventToMouseEvent(aOSEvent, mouseEvent, NS_MOUSE_LEFT_BUTTON_DOWN);
nsWindow* widgetHit = (nsWindow*)mouseEvent.widget;
if (widgetHit)
{
// set the focus on the widget hit, if it accepts it
if (widgetHit->AcceptFocusOnClick())
{
nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)widgetHit->GetToolkit()) );
if (toolkit)
toolkit->SetFocus(widgetHit);
}
// dispatch the event
retVal = widgetHit->DispatchMouseEvent(mouseEvent);
}
if (mLastWidgetHit)
mLastWidgetHit->RemoveDeleteObserver(this);
mLastWidgetHit = widgetHit;
mMouseInWidgetHit = PR_TRUE;
if (mLastWidgetHit)
mLastWidgetHit->AddDeleteObserver(this);
break;
}
case inZoomIn:
case inZoomOut:
{
// Now that we have found the partcode it is ok to actually zoom the window
ZoomWindow(whichWindow, partCode, (whichWindow == FrontWindow()));
#if TARGET_CARBON
Rect macRect;
::GetWindowPortBounds(whichWindow, &macRect);
#else
Rect macRect = whichWindow->portRect;
#endif
::LocalToGlobal(&topLeft(macRect));
::LocalToGlobal(&botRight(macRect));
mTopLevelWidget->Resize(macRect.right - macRect.left, macRect.bottom - macRect.top, PR_FALSE);
break;
}
}
return retVal;
}
//-------------------------------------------------------------------------
//
// HandleMouseUpEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleMouseUpEvent(
EventRecord& aOSEvent)
{
PRBool retVal = PR_FALSE;
nsMouseEvent mouseEvent;
ConvertOSEventToMouseEvent(aOSEvent, mouseEvent, NS_MOUSE_LEFT_BUTTON_UP);
nsWindow* widgetReleased = (nsWindow*)mouseEvent.widget;
if ((widgetReleased != nsnull) && (widgetReleased != mLastWidgetHit))
retVal |= widgetReleased->DispatchMouseEvent(mouseEvent);
if (mLastWidgetHit)
{
mLastWidgetHit->RemoveDeleteObserver(this);
mouseEvent.widget = mLastWidgetHit;
retVal |= mLastWidgetHit->DispatchMouseEvent(mouseEvent);
mLastWidgetHit = nsnull;
}
return retVal;
}
//-------------------------------------------------------------------------
//
// HandleMouseMoveEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleMouseMoveEvent(
EventRecord& aOSEvent)
{
PRBool retVal = PR_FALSE;
nsMouseEvent mouseEvent;
ConvertOSEventToMouseEvent(aOSEvent, mouseEvent, NS_MOUSE_MOVE);
if (mLastWidgetHit)
{
Point macPoint = aOSEvent.where;
::GlobalToLocal(&macPoint);
PRBool inWidgetHit = mLastWidgetHit->PointInWidget(macPoint);
if (inWidgetHit != mMouseInWidgetHit)
{
mouseEvent.message = (inWidgetHit ? NS_MOUSE_ENTER : NS_MOUSE_EXIT);
mMouseInWidgetHit = inWidgetHit;
}
retVal |= mLastWidgetHit->DispatchMouseEvent(mouseEvent);
}
else
{
nsWindow* widgetPointed = (nsWindow*)mouseEvent.widget;
if (widgetPointed != mLastWidgetPointed)
{
if (mLastWidgetPointed)
{
mLastWidgetPointed->RemoveDeleteObserver(this);
mouseEvent.widget = mLastWidgetPointed;
mouseEvent.message = NS_MOUSE_EXIT;
retVal |= mLastWidgetPointed->DispatchMouseEvent(mouseEvent);
mLastWidgetPointed = nsnull;
mouseEvent.widget = widgetPointed;
}
if (widgetPointed)
{
widgetPointed->AddDeleteObserver(this);
mLastWidgetPointed = widgetPointed;
mouseEvent.message = NS_MOUSE_ENTER;
retVal |= widgetPointed->DispatchMouseEvent(mouseEvent);
}
}
else
{
if (widgetPointed)
retVal |= widgetPointed->DispatchMouseEvent(mouseEvent);
}
}
return retVal;
}
#pragma mark -
//-------------------------------------------------------------------------
//
// ConvertOSEventToMouseEvent
//
//-------------------------------------------------------------------------
void nsMacEventHandler::ConvertOSEventToMouseEvent(
EventRecord& aOSEvent,
nsMouseEvent& aMouseEvent,
PRUint32 aMessage)
{
static long lastWhen = 0;
static Point lastWhere = {0, 0};
static short lastClickCount = 0;
// get the click count
if (((aOSEvent.when - lastWhen) < ::LMGetDoubleTime())
&& (abs(aOSEvent.where.h - lastWhere.h) < 5)
&& (abs(aOSEvent.where.v - lastWhere.v) < 5))
{
if (aOSEvent.what == mouseDown)
{
lastClickCount ++;
if (lastClickCount == 2)
aMessage = NS_MOUSE_LEFT_DOUBLECLICK;
}
}
else
{
if (! ::StillDown())
lastClickCount = 0;
}
lastWhen = aOSEvent.when;
lastWhere = aOSEvent.where;
// get the widget hit and the hit point inside that widget
Point hitPoint = aOSEvent.where;
#if TARGET_CARBON
GrafPtr grafPort = reinterpret_cast<GrafPtr>(mTopLevelWidget->GetNativeData(NS_NATIVE_GRAPHIC));
::SetPort(grafPort);
Rect savePortRect;
::GetPortBounds(grafPort, &savePortRect);
#else
GrafPtr grafPort = static_cast<GrafPort*>(mTopLevelWidget->GetNativeData(NS_NATIVE_GRAPHIC));
::SetPort(grafPort);
Rect savePortRect = grafPort->portRect;
#endif
::SetOrigin(0, 0);
::GlobalToLocal(&hitPoint);
::SetOrigin(savePortRect.left, savePortRect.top);
nsPoint widgetHitPoint(hitPoint.h, hitPoint.v);
// if the mouse button is still down, send events to the last widget hit
nsWindow* widgetHit = nsnull;
if (mLastWidgetHit)
{
if (::StillDown() || aMessage == NS_MOUSE_LEFT_BUTTON_UP)
widgetHit = mLastWidgetHit;
else
{
// Patch: some widgets can eat mouseUp events (text widgets in TEClick, sbars in TrackControl).
// In that case, fall back to the normal case.
mLastWidgetHit->RemoveDeleteObserver(this);
mLastWidgetHit = nsnull;
}
}
if (! widgetHit)
widgetHit = mTopLevelWidget->FindWidgetHit(hitPoint);
if (widgetHit)
{
nsRect bounds;
widgetHit->GetBounds(bounds);
nsPoint widgetOrigin(bounds.x, bounds.y);
widgetHit->LocalToWindowCoordinate(widgetOrigin);
widgetHitPoint.MoveBy(-widgetOrigin.x, -widgetOrigin.y);
}
// nsEvent
aMouseEvent.eventStructType = NS_MOUSE_EVENT;
aMouseEvent.message = aMessage;
aMouseEvent.point = widgetHitPoint;
aMouseEvent.time = PR_IntervalNow();
// nsGUIEvent
aMouseEvent.widget = widgetHit;
aMouseEvent.nativeMsg = (void*)&aOSEvent;
// nsInputEvent
aMouseEvent.isShift = ((aOSEvent.modifiers & shiftKey) != 0);
aMouseEvent.isControl = ((aOSEvent.modifiers & controlKey) != 0);
aMouseEvent.isAlt = ((aOSEvent.modifiers & optionKey) != 0);
aMouseEvent.isCommand = ((aOSEvent.modifiers & cmdKey) != 0);
// nsMouseEvent
aMouseEvent.clickCount = lastClickCount;
}
//-------------------------------------------------------------------------
//
// HandlePositionToOffsetEvent
//
//-------------------------------------------------------------------------
long nsMacEventHandler::HandlePositionToOffset(Point aPoint,short* regionClass)
{
*regionClass = kTSMOutsideOfBody;
return 0;
}
//-------------------------------------------------------------------------
//
// HandleOffsetToPosition Event
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleOffsetToPosition(long offset,Point* thePoint)
{
(*thePoint).v = 0;
(*thePoint).h = 0;
return PR_TRUE;
}
//-------------------------------------------------------------------------
//
// HandleUpdate Event
//
//-------------------------------------------------------------------------
nsMacEventHandler::HandleUpdate(Handle textHandle,ScriptCode script,long fixedLength)
{
TextToUnicodeInfo textToUnicodeInfo;
TextEncoding textEncodingFromScript;
ByteCount text_size, source_read;
PRBool rv;
OSErr err;
HLock(textHandle);
//
// if we aren't in composition mode alredy, signal the backing store w/ the mode change
//
if (!mIMEIsComposing) {
mIMEIsComposing = PR_TRUE;
HandleStartComposition();
}
//
// convert our script code (smKeyScript) to a TextEncoding
//
err = ::UpgradeScriptInfoToTextEncoding(script,kTextLanguageDontCare,kTextRegionDontCare,nsnull,
&textEncodingFromScript);
NS_ASSERTION(err==noErr,"nsMacEventHandler::HandleUpdate: UpgradeScriptInfoToTextEncoding failed.");
if (err!=noErr) { ::HUnlock(textHandle); return PR_FALSE; }
err = ::CreateTextToUnicodeInfoByEncoding(textEncodingFromScript,&textToUnicodeInfo);
NS_ASSERTION(err==noErr,"nsMacEventHandler::HandleUpdate: CreateUnicodeToTextInfoByEncoding failed.");
if (err!=noErr) { ::HUnlock(textHandle); return PR_FALSE; }
text_size = ::GetHandleSize(textHandle);
if (mIMECompositionStringSize < (text_size+1)*3) {
mIMECompositionStringSize = (text_size+1)*3;
if (mIMECompositionString!=nsnull) delete [] mIMECompositionString;
mIMECompositionString = new PRUnichar[(text_size+1)*3];
}
//
// convert the text from the Update event into Unicode
//
err = ::ConvertFromTextToUnicode(textToUnicodeInfo,
text_size,*textHandle,
kUnicodeLooseMappingsMask,
0,NULL,NULL,NULL,
mIMECompositionStringSize*sizeof(PRUnichar),&source_read,
&mIMECompositionStringLength,mIMECompositionString);
NS_ASSERTION(err==noErr,"nsMacEventHandler::HandleUpdate: ConverFromTextToUnicode failed.");
if (err!=noErr) { ::HUnlock(textHandle); ::DisposeTextToUnicodeInfo(&textToUnicodeInfo); return PR_FALSE; }
//
// null terminate the string for the XP-stuff
//
mIMECompositionString[mIMECompositionStringLength/sizeof(PRUnichar)] = (PRUnichar)0;
rv = HandleTextEvent();
::HUnlock(textHandle);
::DisposeTextToUnicodeInfo(&textToUnicodeInfo);
if (fixedLength==-1 || fixedLength==text_size) {
HandleEndComposition();
mIMEIsComposing = PR_FALSE;
}
return rv;
}
//-------------------------------------------------------------------------
//
// HandleStartComposition
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleStartComposition(void)
{
//
// get the focused widget [tague: may need to rethink this later]
//
nsWindow* focusedWidget = mTopLevelWidget;
nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)mTopLevelWidget->GetToolkit()) );
if (toolkit)
focusedWidget = toolkit->GetFocus();
if (!focusedWidget)
return PR_FALSE;
//
// create the nsCompositionEvent
//
nsCompositionEvent compositionEvent;
compositionEvent.eventStructType = NS_COMPOSITION_START;
compositionEvent.message = NS_COMPOSITION_START;
compositionEvent.point.x = 0;
compositionEvent.point.y = 0;
compositionEvent.time = PR_IntervalNow();
//
// nsGUIEvent parts
//
compositionEvent.widget = focusedWidget;
compositionEvent.nativeMsg = (void*)nsnull; // no native message for this
return(focusedWidget->DispatchWindowEvent(compositionEvent));
}
//-------------------------------------------------------------------------
//
// HandleEndComposition
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleEndComposition(void)
{
//
// get the focused widget [tague: may need to rethink this later]
//
nsWindow* focusedWidget = mTopLevelWidget;
nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)mTopLevelWidget->GetToolkit()) );
if (toolkit)
focusedWidget = toolkit->GetFocus();
if (!focusedWidget)
return PR_FALSE;
//
// create the nsCompositionEvent
//
nsCompositionEvent compositionEvent;
compositionEvent.eventStructType = NS_COMPOSITION_END;
compositionEvent.message = NS_COMPOSITION_END;
compositionEvent.point.x = 0;
compositionEvent.point.y = 0;
compositionEvent.time = PR_IntervalNow();
//
// nsGUIEvent parts
//
compositionEvent.widget = focusedWidget;
compositionEvent.nativeMsg = (void*)nsnull; // no native message for this
return(focusedWidget->DispatchWindowEvent(compositionEvent));
}
//-------------------------------------------------------------------------
//
// HandleTextEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleTextEvent(void)
{
//
// get the focused widget [tague: may need to rethink this later]
//
nsWindow* focusedWidget = mTopLevelWidget;
nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)mTopLevelWidget->GetToolkit()) );
if (toolkit)
focusedWidget = toolkit->GetFocus();
if (!focusedWidget)
return PR_FALSE;
//
// create the nsCompositionEvent
//
nsTextEvent textEvent;
textEvent.eventStructType = NS_TEXT_EVENT;
textEvent.message = NS_TEXT_EVENT;
textEvent.point.x = 0;
textEvent.point.y = 0;
textEvent.time = PR_IntervalNow();
textEvent.theText = mIMECompositionString;
//
// nsGUIEvent parts
//
textEvent.widget = focusedWidget;
textEvent.nativeMsg = (void*)nsnull; // no native message for this
if (focusedWidget->DispatchWindowEvent(textEvent)==NS_OK)
return PR_TRUE;
else
return PR_FALSE;
}