337199 Key event/text input regressions on Mac after bug 332579, RETURN key events double-processed. Also: 337277 Typed characters appear twice after visiting site with Java applet, 337338 Typing special characters (accents) and symbols with Option fails, 337370 Japanese IME broken, 336357 Keystrokes inserted twice into text input fields. Rework key event and TSM handlers. r=josh sr=shaver a/1.8.1=me&shaver

This commit is contained in:
mark%moxienet.com 2006-05-22 00:34:35 +00:00
Родитель 7c0f0104b8
Коммит 51999bb9af
9 изменённых файлов: 204 добавлений и 115 удалений

Просмотреть файл

@ -103,7 +103,6 @@ CPPSRCS = nsAppShell.cpp \
nsMimeMapper.cpp \
nsNativeThemeMac.cpp \
nsSound.cpp \
nsTSMStrategy.cpp \
nsToolkitBase.cpp \
nsToolkit.cpp \
nsWidgetFactory.cpp \

Просмотреть файл

@ -49,13 +49,8 @@
#include "nsCarbonHelpers.h"
#include "nsIRollupListener.h"
#include "nsIMenuRollup.h"
#include "nsTSMStrategy.h"
#include "nsGfxUtils.h"
#ifndef XP_MACOSX
#include <locale>
#endif
#define PINK_PROFILING_ACTIVATE 0
#if PINK_PROFILING_ACTIVATE
#include "profilerutils.h"
@ -92,20 +87,6 @@ nsMacEventDispatchHandler gEventDispatchHandler;
static void ConvertKeyEventToContextMenuEvent(const nsKeyEvent* inKeyEvent, nsMouseEvent* outCMEvent);
static inline PRBool IsContextMenuKey(const nsKeyEvent& inKeyEvent);
class StPackedBoolSetter {
public:
StPackedBoolSetter(PRPackedBool& aFlag): mFlag(aFlag) {
mFlag = PR_TRUE;
};
~StPackedBoolSetter() {
mFlag = PR_FALSE;
};
protected:
PRPackedBool& mFlag;
};
//-------------------------------------------------------------------------
//
@ -362,23 +343,17 @@ void nsMacEventDispatchHandler::SetGlobalPoint(Point inPoint)
//-------------------------------------------------------------------------
nsMacEventHandler::nsMacEventHandler(nsMacWindow* aTopLevelWidget)
{
OSErr err;
InterfaceTypeList supportedServices;
mTopLevelWidget = aTopLevelWidget;
nsTSMStrategy tsmstrategy;
//
// create a TSMDocument for this window. We are allocating a TSM document for
// each Mac window
//
mTSMDocument = nsnull;
if (tsmstrategy.UseUnicodeForInputMethod()) {
supportedServices[0] = kUnicodeDocument;
} else {
supportedServices[0] = kTextService;
}
OSErr err;
InterfaceTypeList supportedServices;
mTopLevelWidget = aTopLevelWidget;
//
// create a TSMDocument for this window. We are allocating a TSM document for
// each Mac window
//
mTSMDocument = nsnull;
supportedServices[0] = kUnicodeDocument;
err = ::NewTSMDocument(1, supportedServices,&mTSMDocument, (long)this);
NS_ASSERTION(err==noErr, "nsMacEventHandler::nsMacEventHandler: NewTSMDocument failed.");
#ifdef DEBUG_TSM
@ -393,7 +368,8 @@ nsMacEventHandler::nsMacEventHandler(nsMacWindow* aTopLevelWidget)
mIMEIsComposing = PR_FALSE;
mIMECompositionStr = nsnull;
mHandlingKeyEvent = PR_FALSE;
mKeyIgnore = PR_FALSE;
mKeyHandled = PR_FALSE;
}
@ -690,10 +666,8 @@ enum
};
static PRUint32 ConvertMacToRaptorKeyCode(UInt32 eventMessage, UInt32 eventModifiers)
static PRUint32 ConvertMacToRaptorKeyCode(char charCode, UInt32 keyCode, UInt32 eventModifiers)
{
UInt8 charCode = (eventMessage & charCodeMask);
UInt8 keyCode = (eventMessage & keyCodeMask) >> 8;
PRUint32 raptorKeyCode = 0;
switch (keyCode)
@ -881,7 +855,7 @@ void nsMacEventHandler::InitializeKeyEvent(nsKeyEvent& aKeyEvent,
} // if (message == NS_KEY_PRESS && !IsSpecialRaptorKey((aOSEvent.message & keyCodeMask) >> 8) )
else
{
aKeyEvent.keyCode = ConvertMacToRaptorKeyCode(aOSEvent.message, aOSEvent.modifiers);
aKeyEvent.keyCode = ConvertMacToRaptorKeyCode(aOSEvent.message & charCodeMask, (aOSEvent.message & keyCodeMask) >> 8, aOSEvent.modifiers);
aKeyEvent.charCode = 0;
} // else for if (message == NS_KEY_PRESS && !IsSpecialRaptorKey((aOSEvent.message & keyCodeMask) >> 8) )
@ -1045,12 +1019,6 @@ PRUint32 nsMacEventHandler::ConvertKeyEventToUnicode(EventRecord& aOSEvent)
PRBool nsMacEventHandler::HandleKeyEvent(EventRecord& aOSEvent)
{
// Avoid reentrancy
if (mHandlingKeyEvent)
return PR_FALSE;
StPackedBoolSetter handling(mHandlingKeyEvent);
nsresult result = NS_ERROR_UNEXPECTED;
nsWindow* checkFocusedWidget;
@ -1166,34 +1134,17 @@ IsContextMenuKey(const nsKeyEvent& inKeyEvent)
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleUKeyEvent(const PRUnichar* text, long charCount, EventRecord& aOSEvent)
{
// Avoid reentrancy
if (mHandlingKeyEvent)
// The focused widget changed in HandleKeyUpDownEvent, so no NS_KEY_PRESS
// events should be generated.
if (mKeyIgnore)
return PR_FALSE;
StPackedBoolSetter handling(mHandlingKeyEvent);
nsresult result = NS_ERROR_UNEXPECTED;
// get the focused widget
nsWindow* focusedWidget = gEventDispatchHandler.GetActive();
if (!focusedWidget)
focusedWidget = mTopLevelWidget;
// simulate key down event if this isn't an autoKey event
if (aOSEvent.what == keyDown)
{
nsKeyEvent keyDownEvent(PR_TRUE, NS_KEY_DOWN, nsnull);
InitializeKeyEvent(keyDownEvent, aOSEvent, focusedWidget, NS_KEY_DOWN, PR_FALSE);
result = focusedWidget->DispatchWindowEvent(keyDownEvent);
NS_ASSERTION(NS_SUCCEEDED(result), "cannot DispatchWindowEvent keydown");
// check if focus changed; see also HandleKeyEvent above
nsWindow *checkFocusedWidget = gEventDispatchHandler.GetActive();
if (!checkFocusedWidget)
checkFocusedWidget = mTopLevelWidget;
if (checkFocusedWidget != focusedWidget)
return result;
}
// simulate key press events
if (!IsSpecialRaptorKey((aOSEvent.message & keyCodeMask) >> 8))
{
@ -1205,6 +1156,10 @@ PRBool nsMacEventHandler::HandleUKeyEvent(const PRUnichar* text, long charCount,
InitializeKeyEvent(keyPressEvent, aOSEvent, focusedWidget, NS_KEY_PRESS, PR_FALSE);
keyPressEvent.charCode = text[i];
// If keydown default was prevented, do same for keypress
if (mKeyHandled)
keyPressEvent.flags |= NS_EVENT_FLAG_NO_DEFAULT;
// control key is special in that it doesn't give us letters
// it generates a charcode of 0x01 for control-a
// so we offset to do the right thing for gecko (as in HandleKeyEvent)
@ -2669,3 +2624,100 @@ nsresult nsMacEventHandler::ResetInputState()
return NS_OK;
}
PRBool
nsMacEventHandler::HandleKeyUpDownEvent(EventHandlerCallRef aHandlerCallRef,
EventRef aEvent)
{
PRUint32 eventKind = ::GetEventKind(aEvent);
NS_ASSERTION(eventKind == kEventRawKeyDown ||
eventKind == kEventRawKeyUp,
"Unknown event kind");
PRBool handled = PR_FALSE;
nsWindow* focusedWidget = gEventDispatchHandler.GetActive();
if (!focusedWidget)
focusedWidget = mTopLevelWidget;
PRUint32 modifiers = 0;
OSStatus err = ::GetEventParameter(aEvent, kEventParamKeyModifiers,
typeUInt32, NULL,
sizeof(modifiers), NULL,
&modifiers);
NS_ASSERTION(err == noErr, "Could not get kEventParamKeyModifiers");
PRUint32 keyCode = 0;
err = ::GetEventParameter(aEvent, kEventParamKeyCode,
typeUInt32, NULL,
sizeof(keyCode), NULL,
&keyCode);
NS_ASSERTION(err == noErr, "Could not get kEventParamKeyCode");
PRUint8 charCode = 0;
::GetEventParameter(aEvent, kEventParamKeyMacCharCodes,
typeChar, NULL,
sizeof(charCode), NULL,
&charCode);
// Failure is not a fatal condition.
// The event's nativeMsg field historically held an EventRecord. Some
// consumers (plugins) rely on this behavior. Note that
// ConvertEventRefToEventRecord can return false and produce a null
// event record in some cases, such as when entering an IME session.
EventRecord eventRecord;
::ConvertEventRefToEventRecord(aEvent, &eventRecord);
// kEventRawKeyDown or kEventRawKeyUp only
PRUint32 message = (eventKind == kEventRawKeyUp ? NS_KEY_UP : NS_KEY_DOWN);
nsKeyEvent upDownEvent(PR_TRUE, message, nsnull);
upDownEvent.time = PR_IntervalNow();
upDownEvent.widget = focusedWidget;
upDownEvent.nativeMsg = (void*)&eventRecord;
upDownEvent.isShift = ((modifiers & shiftKey) != 0);
upDownEvent.isControl = ((modifiers & controlKey) != 0);
upDownEvent.isAlt = ((modifiers & optionKey) != 0);
upDownEvent.isMeta = ((modifiers & cmdKey) != 0);
upDownEvent.keyCode = ConvertMacToRaptorKeyCode(charCode, keyCode,
modifiers);
upDownEvent.charCode = 0;
handled = focusedWidget->DispatchWindowEvent(upDownEvent);
if (eventKind == kEventRawKeyUp)
return handled;
// kEventRawKeyDown only. Prepare for a possible NS_KEY_PRESS event.
nsWindow* checkFocusedWidget = gEventDispatchHandler.GetActive();
if (!checkFocusedWidget)
checkFocusedWidget = mTopLevelWidget;
// Set a flag indicating that NS_KEY_PRESS events should not be dispatched,
// because focus changed.
PRBool lastIgnore = PR_FALSE;
if (checkFocusedWidget != focusedWidget) {
lastIgnore = mKeyIgnore;
mKeyIgnore = PR_TRUE;
}
// Set a flag indicating that the NS_KEY_DOWN event came back with
// preventDefault, and NS_KEY_PRESS events should have the same flag set.
PRBool lastHandled = PR_FALSE;
if (handled) {
lastHandled = mKeyHandled;
mKeyHandled = PR_TRUE;
}
// The event needs further processing.
// - If no input method is active, an event will be delivered to the
// kEventTextInputUnicodeForKeyEvent handler, which will call
// HandleUKeyEvent, which takes care of dispatching NS_KEY_PRESS events.
// - If an input method is active, an event will be delivered to the
// kEventTextInputUpdateActiveInputArea handler, which will call
// UnicodeHandleUpdateInputArea to handle the input session.
::CallNextEventHandler(aHandlerCallRef, aEvent);
mKeyHandled = lastHandled;
mKeyIgnore = lastIgnore;
return handled;
}

Просмотреть файл

@ -131,6 +131,8 @@ public:
virtual nsresult HandleUnicodeGetSelectedText(nsAString& outString);
virtual nsresult ResetInputState();
virtual PRBool HandleUKeyEvent(const PRUnichar* text, long charCount, EventRecord& aOSEvent);
virtual PRBool HandleKeyUpDownEvent(EventHandlerCallRef aHandlerCallRef,
EventRef aEvent);
//
// Synthetic events, generated internally to do things at specific times and
@ -172,7 +174,8 @@ protected:
nsPoint mIMEPos;
nsAutoString *mIMECompositionStr;
PRPackedBool mIMEIsComposing;
PRPackedBool mHandlingKeyEvent;
PRPackedBool mKeyIgnore;
PRPackedBool mKeyHandled;
};
#endif // MacMacEventHandler_h__

Просмотреть файл

@ -81,9 +81,12 @@ nsMacMessagePump::nsMacMessagePump(nsToolkit *aToolkit)
{ kEventClassMouse, kEventMouseUp },
{ kEventClassMouse, kEventMouseMoved },
{ kEventClassMouse, kEventMouseDragged },
#if 0
// These are now handled by nsMacWindow::KeyEventHandler
{ kEventClassKeyboard, kEventRawKeyDown },
{ kEventClassKeyboard, kEventRawKeyUp },
{ kEventClassKeyboard, kEventRawKeyRepeat },
#endif
{ kEventClassWindow, kEventWindowUpdate },
{ kEventClassWindow, kEventWindowActivated },
{ kEventClassWindow, kEventWindowDeactivated },

Просмотреть файл

@ -42,7 +42,6 @@
#include <Script.h>
#include <TextServices.h>
#include <AEDataModel.h>
#include "nsTSMStrategy.h"
#include "nsCarbonHelpers.h"
@ -67,7 +66,6 @@ AEEventHandlerUPP nsMacTSMMessagePump::mGetSelectedTextUPP = NULL;
nsMacTSMMessagePump::nsMacTSMMessagePump()
{
OSErr err;
nsTSMStrategy tsmstrategy;
mPos2OffsetUPP = NewAEEventHandlerUPP(nsMacTSMMessagePump::PositionToOffsetHandler);
NS_ASSERTION(mPos2OffsetUPP!=NULL, "nsMacTSMMessagePump::InstallTSMAEHandlers: NewAEEventHandlerUPP[Pos2Pffset] failed");
@ -75,11 +73,7 @@ nsMacTSMMessagePump::nsMacTSMMessagePump()
mOffset2PosUPP = NewAEEventHandlerUPP(nsMacTSMMessagePump::OffsetToPositionHandler);
NS_ASSERTION(mPos2OffsetUPP!=NULL, "nsMacTSMMessagePump::InstallTSMAEHandlers: NewAEEventHandlerUPP[Pos2Pffset] failed");
if (tsmstrategy.UseUnicodeForInputMethod()) {
mUpdateUPP = NewAEEventHandlerUPP(nsMacTSMMessagePump::UnicodeUpdateHandler);
} else {
mUpdateUPP = NewAEEventHandlerUPP(nsMacTSMMessagePump::UpdateHandler);
}
mUpdateUPP = NewAEEventHandlerUPP(nsMacTSMMessagePump::UnicodeUpdateHandler);
NS_ASSERTION(mPos2OffsetUPP!=NULL, "nsMacTSMMessagePump::InstallTSMAEHandlers: NewAEEventHandlerUPP[Pos2Pffset] failed");
err = AEInstallEventHandler(kTextServiceClass, kPos2Offset, mPos2OffsetUPP, (long)this, false);
@ -91,20 +85,17 @@ nsMacTSMMessagePump::nsMacTSMMessagePump()
err = AEInstallEventHandler(kTextServiceClass, kUpdateActiveInputArea, mUpdateUPP, (long)this, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandler[Update] failed");
if (tsmstrategy.UseUnicodeForKeyboard()) {
mKeyboardUPP = NewAEEventHandlerUPP(nsMacTSMMessagePump::UnicodeNotFromInputMethodHandler);
NS_ASSERTION(mKeyboardUPP!=NULL, "nsMacTSMMessagePump::InstallTSMAEHandlers: NewAEEventHandlerUPP[FromInputMethod] failed");
mKeyboardUPP = NewAEEventHandlerUPP(nsMacTSMMessagePump::UnicodeNotFromInputMethodHandler);
NS_ASSERTION(mKeyboardUPP!=NULL, "nsMacTSMMessagePump::InstallTSMAEHandlers: NewAEEventHandlerUPP[FromInputMethod] failed");
err = AEInstallEventHandler(kTextServiceClass, kUnicodeNotFromInputMethod, mKeyboardUPP, (long)this, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandler[FromInputMethod] failed");
err = AEInstallEventHandler(kTextServiceClass, kUnicodeNotFromInputMethod, mKeyboardUPP, (long)this, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandler[FromInputMethod] failed");
mGetSelectedTextUPP = NewAEEventHandlerUPP(nsMacTSMMessagePump::UnicodeGetSelectedTextHandler);
NS_ASSERTION(mGetSelectedTextUPP!=NULL, "nsMacTSMMessagePump::InstallTSMAEHandlers: NewAEEventHandlerUPP[GetSelectedText] failed");
mGetSelectedTextUPP = NewAEEventHandlerUPP(nsMacTSMMessagePump::UnicodeGetSelectedTextHandler);
NS_ASSERTION(mGetSelectedTextUPP!=NULL, "nsMacTSMMessagePump::InstallTSMAEHandlers: NewAEEventHandlerUPP[GetSelectedText] failed");
err = AEInstallEventHandler(kTextServiceClass, kGetSelectedText, mGetSelectedTextUPP, (long)this, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandler[GetSelectedText] failed");
}
err = AEInstallEventHandler(kTextServiceClass, kGetSelectedText, mGetSelectedTextUPP, (long)this, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::InstallTSMAEHandlers: AEInstallEventHandler[GetSelectedText] failed");
}
@ -125,16 +116,13 @@ nsMacTSMMessagePump::~nsMacTSMMessagePump()
::DisposeAEEventHandlerUPP(mOffset2PosUPP);
::DisposeAEEventHandlerUPP(mUpdateUPP);
nsTSMStrategy tsmstrategy;
if (tsmstrategy.UseUnicodeForKeyboard()) {
err = AERemoveEventHandler(kTextServiceClass, kUnicodeNotFromInputMethod, mKeyboardUPP, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::RemoveTSMAEHandlers: AERemoveEventHandler[FromInputMethod] failed");
::DisposeAEEventHandlerUPP(mKeyboardUPP);
err = AERemoveEventHandler(kTextServiceClass, kUnicodeNotFromInputMethod, mKeyboardUPP, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::RemoveTSMAEHandlers: AERemoveEventHandler[FromInputMethod] failed");
::DisposeAEEventHandlerUPP(mKeyboardUPP);
err = AERemoveEventHandler(kTextServiceClass, kGetSelectedText, mGetSelectedTextUPP, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::RemoveTSMAEHandlers: AERemoveEventHandler[GetSelectedText] failed");
::DisposeAEEventHandlerUPP(mGetSelectedTextUPP);
}
err = AERemoveEventHandler(kTextServiceClass, kGetSelectedText, mGetSelectedTextUPP, false);
NS_ASSERTION(err==noErr, "nsMacTSMMessagePump::RemoveTSMAEHandlers: AERemoveEventHandler[GetSelectedText] failed");
::DisposeAEEventHandlerUPP(mGetSelectedTextUPP);
}

Просмотреть файл

@ -563,25 +563,25 @@ nsresult nsMacWindow::StandardCreate(nsIWidget *aParent,
if ( mWindowType != eWindowType_invisible &&
mWindowType != eWindowType_plugin &&
mWindowType != eWindowType_java) {
const EventTypeSpec scrollEventList[] = {
{ kEventClassMouse, kEventMouseWheelMoved }
const EventTypeSpec kScrollEventList[] = {
{ kEventClassMouse, kEventMouseWheelMoved },
};
// note, passing NULL as the final param to IWEH() causes the UPP to be
// disposed automatically when the event target (the window) goes away.
// See CarbonEvents.h for info.
err = ::InstallWindowEventHandler(mWindowPtr,
NewEventHandlerUPP(ScrollEventHandler),
GetEventTypeCount(scrollEventList),
scrollEventList, this, NULL);
NS_ASSERTION(err == noErr,
"Couldn't install Carbon Scroll Event handlers");
static EventHandlerUPP sScrollEventHandlerUPP;
if (!sScrollEventHandlerUPP)
sScrollEventHandlerUPP = ::NewEventHandlerUPP(ScrollEventHandler);
err = ::InstallWindowEventHandler(mWindowPtr,
sScrollEventHandlerUPP,
GetEventTypeCount(kScrollEventList),
kScrollEventList,
(void*)this,
NULL);
NS_ASSERTION(err == noErr, "Couldn't install scroll event handler");
}
// Since we can only call IWEH() once for each event class such as
// kEventClassWindow, we register all the event types that we are going to
// handle here.
const EventTypeSpec windEventList[] = {
// Window event handler
const EventTypeSpec kWindowEventList[] = {
// to enable live resizing
{ kEventClassWindow, kEventWindowBoundsChanged },
// to roll up popups when we're minimized
@ -594,12 +594,35 @@ nsresult nsMacWindow::StandardCreate(nsIWidget *aParent,
{ kEventClassWindow, kEventWindowUpdate },
};
PRUint32 typeCount = GetEventTypeCount(windEventList);
static EventHandlerUPP sWindowEventHandlerUPP;
if (!sWindowEventHandlerUPP)
sWindowEventHandlerUPP = ::NewEventHandlerUPP(WindowEventHandler);
err = ::InstallWindowEventHandler(mWindowPtr,
NewEventHandlerUPP(WindowEventHandler),
typeCount, windEventList, this, NULL);
NS_ASSERTION(err == noErr, "Couldn't install sheet Event handlers");
sWindowEventHandlerUPP,
GetEventTypeCount(kWindowEventList),
kWindowEventList,
(void*)this,
NULL);
NS_ASSERTION(err == noErr, "Couldn't install window event handler");
// Key event handler
const EventTypeSpec kKeyEventList[] = {
{ kEventClassKeyboard, kEventRawKeyDown },
{ kEventClassKeyboard, kEventRawKeyUp },
};
static EventHandlerUPP sKeyEventHandlerUPP;
if (!sKeyEventHandlerUPP)
sKeyEventHandlerUPP = ::NewEventHandlerUPP(KeyEventHandler);
err = ::InstallWindowEventHandler(mWindowPtr,
sKeyEventHandlerUPP,
GetEventTypeCount(kKeyEventList),
kKeyEventList,
NS_STATIC_CAST(void*, this),
NULL);
NS_ASSERTION(err == noErr, "Couldn't install key event handler");
// register tracking and receive handlers with the native Drag Manager
if ( mDragTrackingHandlerUPP ) {
@ -2193,3 +2216,21 @@ NS_IMETHODIMP nsMacWindow::Update()
return rv;
}
pascal OSStatus
nsMacWindow::KeyEventHandler(EventHandlerCallRef aHandlerCallRef,
EventRef aEvent,
void* aUserData)
{
nsMacWindow* self = NS_STATIC_CAST(nsMacWindow*, aUserData);
NS_ASSERTION(self, "No self?");
NS_ASSERTION(self->mMacEventHandler.get(), "No mMacEventHandler?");
PRBool handled = self->mMacEventHandler->HandleKeyUpDownEvent(aHandlerCallRef,
aEvent);
if (!handled)
return eventNotHandledErr;
return noErr;
}

Просмотреть файл

@ -151,6 +151,9 @@ protected:
EventRef inEvent, void* userData ) ;
pascal static OSStatus ScrollEventHandler ( EventHandlerCallRef inHandlerChain,
EventRef inEvent, void* userData ) ;
pascal static OSStatus KeyEventHandler(EventHandlerCallRef aHandlerCallRef,
EventRef aEvent,
void* aUserData);
nsresult GetDesktopRect(Rect* desktopRect);
PRPackedBool mWindowMadeHere; // true if we created the window

Просмотреть файл

Просмотреть файл