Bug 685073 part.1 Manage nested key events for IME r=smichaud

This commit is contained in:
Masayuki Nakano 2011-10-05 11:19:24 +09:00
Родитель 02ee80be8e
Коммит eeb6716dfb
2 изменённых файлов: 110 добавлений и 33 удалений

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

@ -485,6 +485,23 @@ protected:
KeyEventState() : mKeyEvent(nsnull)
{
Clear();
}
KeyEventState(NSEvent* aNativeKeyEvent) : mKeyEvent(nsnull)
{
Clear();
Set(aNativeKeyEvent);
}
KeyEventState(const KeyEventState &aOther) : mKeyEvent(nsnull)
{
Clear();
if (aOther.mKeyEvent) {
mKeyEvent = [aOther.mKeyEvent retain];
}
mKeyDownHandled = aOther.mKeyDownHandled;
mKeyPressDispatched = aOther.mKeyPressDispatched;
mKeyPressHandled = aOther.mKeyPressHandled;
}
~KeyEventState()
@ -529,15 +546,67 @@ protected:
~AutoKeyEventStateCleaner()
{
mHandler->mCurrentKeyEvent.Clear();
mHandler->RemoveCurrentKeyEvent();
}
private:
TextInputHandlerBase* mHandler;
nsRefPtr<TextInputHandlerBase> mHandler;
};
// XXX If keydown event was nested, the key event is overwritten by newer
// event. This is wrong behavior. Some IMEs are making such situation.
KeyEventState mCurrentKeyEvent;
/**
* mCurrentKeyEvents stores all key events which are being processed.
* When we call interpretKeyEvents, IME may generate other key events.
* mCurrentKeyEvents[0] is the latest key event.
*/
nsTArray<KeyEventState*> mCurrentKeyEvents;
/**
* mFirstKeyEvent must be used for first key event. This member prevents
* memory fragmentation for most key events.
*/
KeyEventState mFirstKeyEvent;
/**
* PushKeyEvent() adds the current key event to mCurrentKeyEvents.
*/
KeyEventState* PushKeyEvent(NSEvent* aNativeKeyEvent)
{
KeyEventState* keyEvent = nsnull;
if (mCurrentKeyEvents.Length() == 0) {
mFirstKeyEvent.Set(aNativeKeyEvent);
keyEvent = &mFirstKeyEvent;
} else {
keyEvent = new KeyEventState(aNativeKeyEvent);
}
return *mCurrentKeyEvents.AppendElement(keyEvent);
}
/**
* RemoveCurrentKeyEvent() removes the current key event from
* mCurrentKeyEvents.
*/
void RemoveCurrentKeyEvent()
{
NS_ASSERTION(mCurrentKeyEvents.Length() > 0,
"RemoveCurrentKeyEvent() is called unexpectedly");
KeyEventState* keyEvent = GetCurrentKeyEvent();
mCurrentKeyEvents.RemoveElementAt(mCurrentKeyEvents.Length() - 1);
if (keyEvent == &mFirstKeyEvent) {
keyEvent->Clear();
} else {
delete keyEvent;
}
}
/**
* GetCurrentKeyEvent() returns current processing key event.
*/
KeyEventState* GetCurrentKeyEvent()
{
if (mCurrentKeyEvents.Length() == 0) {
return nsnull;
}
return mCurrentKeyEvents[mCurrentKeyEvents.Length() - 1];
}
/**
* IsPrintableChar() checks whether the unicode character is
@ -1119,7 +1188,8 @@ public:
*/
bool KeyPressWasHandled()
{
return mCurrentKeyEvent.mKeyPressHandled;
KeyEventState* currentKeyEvent = GetCurrentKeyEvent();
return currentKeyEvent && currentKeyEvent->mKeyPressHandled;
}
protected:

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

@ -997,7 +997,7 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
nsRefPtr<nsChildView> kungFuDeathGrip(mWidget);
mCurrentKeyEvent.Set(aNativeEvent);
KeyEventState* currentKeyEvent = PushKeyEvent(aNativeEvent);
AutoKeyEventStateCleaner remover(this);
BOOL nonDeadKeyPress = [[aNativeEvent characters] length] > 0;
@ -1015,12 +1015,12 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
}
#endif // #ifndef NP_NO_CARBON
mCurrentKeyEvent.mKeyDownHandled = DispatchEvent(keydownEvent);
currentKeyEvent->mKeyDownHandled = DispatchEvent(keydownEvent);
if (Destroyed()) {
PR_LOG(gLog, PR_LOG_ALWAYS,
("%p TextInputHandler::HandleKeyDownEvent, "
"widget was destroyed by keydown event", this));
return mCurrentKeyEvent.KeyDownOrPressHandled();
return currentKeyEvent->KeyDownOrPressHandled();
}
// The key down event may have shifted the focus, in which
@ -1030,7 +1030,7 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
PR_LOG(gLog, PR_LOG_ALWAYS,
("%p TextInputHandler::HandleKeyDownEvent, "
"view lost focus by keydown event", this));
return mCurrentKeyEvent.KeyDownOrPressHandled();
return currentKeyEvent->KeyDownOrPressHandled();
}
// If this is the context menu key command, send a context menu key event.
@ -1052,7 +1052,7 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
Destroyed() ? " and widget was destroyed" : ""));
[mView maybeInitContextMenuTracking];
// Bail, there is nothing else to do here.
return (cmEventHandled || mCurrentKeyEvent.KeyDownOrPressHandled());
return (cmEventHandled || currentKeyEvent->KeyDownOrPressHandled());
}
nsKeyEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
@ -1066,16 +1066,16 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
// its owning shortcut key. See bug 477291.
if ((!keypressEvent.isChar || keypressEvent.isControl) &&
!IsIMEComposing()) {
if (mCurrentKeyEvent.mKeyDownHandled) {
if (currentKeyEvent->mKeyDownHandled) {
keypressEvent.flags |= NS_EVENT_FLAG_NO_DEFAULT;
}
mCurrentKeyEvent.mKeyPressHandled = DispatchEvent(keypressEvent);
mCurrentKeyEvent.mKeyPressDispatched = true;
currentKeyEvent->mKeyPressHandled = DispatchEvent(keypressEvent);
currentKeyEvent->mKeyPressDispatched = true;
if (Destroyed()) {
PR_LOG(gLog, PR_LOG_ALWAYS,
("%p TextInputHandler::HandleKeyDownEvent, "
"widget was destroyed by keypress event", this));
return mCurrentKeyEvent.KeyDownOrPressHandled();
return currentKeyEvent->KeyDownOrPressHandled();
}
}
}
@ -1098,7 +1098,7 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
PR_LOG(gLog, PR_LOG_ALWAYS,
("%p TextInputHandler::HandleKeyDownEvent, widget was destroyed",
this));
return mCurrentKeyEvent.KeyDownOrPressHandled();
return currentKeyEvent->KeyDownOrPressHandled();
}
PR_LOG(gLog, PR_LOG_ALWAYS,
@ -1106,7 +1106,7 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
"IsIMEComposing()=%s",
this, TrueOrFalse(wasComposing), TrueOrFalse(IsIMEComposing())));
if (!mCurrentKeyEvent.mKeyPressDispatched && nonDeadKeyPress &&
if (!currentKeyEvent->mKeyPressDispatched && nonDeadKeyPress &&
!wasComposing && !IsIMEComposing()) {
nsKeyEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
InitKeyEvent(aNativeEvent, keypressEvent);
@ -1124,10 +1124,10 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
// our default action for this key.
if (!(interpretKeyEventsCalled &&
IsNormalCharInputtingEvent(keypressEvent))) {
if (mCurrentKeyEvent.mKeyDownHandled) {
if (currentKeyEvent->mKeyDownHandled) {
keypressEvent.flags |= NS_EVENT_FLAG_NO_DEFAULT;
}
mCurrentKeyEvent.mKeyPressHandled = DispatchEvent(keypressEvent);
currentKeyEvent->mKeyPressHandled = DispatchEvent(keypressEvent);
PR_LOG(gLog, PR_LOG_ALWAYS,
("%p TextInputHandler::HandleKeyDownEvent, keypress event dispatched",
this));
@ -1139,9 +1139,9 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
PR_LOG(gLog, PR_LOG_ALWAYS,
("%p TextInputHandler::HandleKeyDownEvent, "
"keydown handled=%s, keypress handled=%s",
this, TrueOrFalse(mCurrentKeyEvent.mKeyDownHandled),
TrueOrFalse(mCurrentKeyEvent.mKeyPressHandled)));
return mCurrentKeyEvent.KeyDownOrPressHandled();
this, TrueOrFalse(currentKeyEvent->mKeyDownHandled),
TrueOrFalse(currentKeyEvent->mKeyPressHandled)));
return currentKeyEvent->KeyDownOrPressHandled();
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
}
@ -1312,13 +1312,17 @@ TextInputHandler::InsertText(NSAttributedString *aAttrString)
return;
}
KeyEventState* currentKeyEvent = GetCurrentKeyEvent();
PR_LOG(gLog, PR_LOG_ALWAYS,
("%p TextInputHandler::InsertText, aAttrString=\"%s\", "
"IsIMEComposing()=%s, IgnoreIMEComposition()=%s, "
"keyevent=%p, keypressDispatched=%s",
this, GetCharacters([aAttrString string]), TrueOrFalse(IsIMEComposing()),
TrueOrFalse(IgnoreIMEComposition()), mCurrentKeyEvent.mKeyEvent,
TrueOrFalse(mCurrentKeyEvent.mKeyPressDispatched)));
TrueOrFalse(IgnoreIMEComposition()),
currentKeyEvent ? currentKeyEvent->mKeyEvent : nsnull,
currentKeyEvent ?
TrueOrFalse(currentKeyEvent->mKeyPressDispatched) : "N/A"));
if (IgnoreIMEComposition()) {
return;
@ -1337,7 +1341,7 @@ TextInputHandler::InsertText(NSAttributedString *aAttrString)
// Don't let the same event be fired twice when hitting
// enter/return! (Bug 420502)
if (mCurrentKeyEvent.mKeyPressDispatched) {
if (currentKeyEvent && currentKeyEvent->mKeyPressDispatched) {
return;
}
@ -1359,8 +1363,8 @@ TextInputHandler::InsertText(NSAttributedString *aAttrString)
EventRecord carbonEvent;
#endif // #ifndef NP_NO_CARBON
if (mCurrentKeyEvent.mKeyEvent) {
NSEvent* keyEvent = mCurrentKeyEvent.mKeyEvent;
if (currentKeyEvent) {
NSEvent* keyEvent = currentKeyEvent->mKeyEvent;
// XXX The ASCII characters inputting mode of egbridge (Japanese IME)
// might send the keyDown event with wrong keyboard layout if other
@ -1373,7 +1377,7 @@ TextInputHandler::InsertText(NSAttributedString *aAttrString)
}
#endif // #ifndef NP_NO_CARBON
if (mCurrentKeyEvent.mKeyDownHandled) {
if (currentKeyEvent->mKeyDownHandled) {
keypressEvent.flags |= NS_EVENT_FLAG_NO_DEFAULT;
}
@ -1400,9 +1404,9 @@ TextInputHandler::InsertText(NSAttributedString *aAttrString)
// Note: mWidget might have become null here. Don't count on it from here on.
if (mCurrentKeyEvent.mKeyEvent) {
mCurrentKeyEvent.mKeyPressHandled = keyPressHandled;
mCurrentKeyEvent.mKeyPressDispatched = true;
if (currentKeyEvent) {
currentKeyEvent->mKeyPressHandled = keyPressHandled;
currentKeyEvent->mKeyPressDispatched = true;
}
NS_OBJC_END_TRY_ABORT_BLOCK;
@ -1411,13 +1415,16 @@ TextInputHandler::InsertText(NSAttributedString *aAttrString)
bool
TextInputHandler::DoCommandBySelector(const char* aSelector)
{
KeyEventState* currentKeyEvent = GetCurrentKeyEvent();
PR_LOG(gLog, PR_LOG_ALWAYS,
("%p TextInputHandler::DoCommandBySelector, aSelector=\"%s\", "
"Destroyed()=%s, keypressHandled=%s",
this, aSelector ? aSelector : "", TrueOrFalse(Destroyed()),
TrueOrFalse(mCurrentKeyEvent.mKeyPressHandled)));
currentKeyEvent ?
TrueOrFalse(currentKeyEvent->mKeyPressHandled) : "N/A"));
return !Destroyed() && mCurrentKeyEvent.mKeyPressHandled;
return !Destroyed() && currentKeyEvent && currentKeyEvent->mKeyPressHandled;
}