Backed out 6 changesets (bug 1343451) for mochitest android perma failures on testInputConnection.

Backed out changeset e07105d9698e (bug 1343451)
Backed out changeset dc4a2a5932c3 (bug 1343451)
Backed out changeset 9561ed261d04 (bug 1343451)
Backed out changeset 84a5ec921442 (bug 1343451)
Backed out changeset b34d48936db8 (bug 1343451)
Backed out changeset 4dce7ab14f71 (bug 1343451)
This commit is contained in:
Cosmin Sabou 2018-03-12 18:07:46 +02:00
parent a1b559f2fa
commit 462b445081
14 changed files with 215 additions and 687 deletions

View File

@ -212,9 +212,6 @@ DEFINE_VK_INTERNAL(_ALTGR)
DEFINE_VK_INTERNAL(_WIN_ICO_HELP)
DEFINE_VK_INTERNAL(_WIN_ICO_00)
DEFINE_VK_INTERNAL(_PROCESSKEY)
DEFINE_VK_INTERNAL(_WIN_ICO_CLEAR)
DEFINE_VK_INTERNAL(_WIN_OEM_RESET)
DEFINE_VK_INTERNAL(_WIN_OEM_JUMP)

View File

@ -195,12 +195,6 @@ interface KeyEvent
// for compatibility with the other web browsers on Windows.
const unsigned long DOM_VK_WIN_ICO_HELP = 0xE3;
const unsigned long DOM_VK_WIN_ICO_00 = 0xE4;
// IME processed key.
const unsigned long DOM_VK_PROCESSKEY = 0xE5;
// OEM specific virtual keyCode of Windows should pass through DOM keyCode
// for compatibility with the other web browsers on Windows.
const unsigned long DOM_VK_WIN_ICO_CLEAR = 0xE6;
const unsigned long DOM_VK_WIN_OEM_RESET = 0xE9;
const unsigned long DOM_VK_WIN_OEM_JUMP = 0xEA;

View File

@ -529,9 +529,6 @@ KEY_MAP_ANDROID (NonConvert, AKEYCODE_MUHENKAN)
// PreviousCandidate
KEY_MAP_GTK (PreviousCandidate, GDK_PreviousCandidate) // OADG 109, Mae Koho
// Process
KEY_MAP_WIN (Process, VK_PROCESSKEY)
// SingleCandidate
KEY_MAP_GTK (SingleCandidate, GDK_SingleCandidate)

View File

@ -668,6 +668,7 @@ GeckoEditableSupport::OnKeyEvent(int32_t aAction, int32_t aKeyCode,
/*
* Send dummy key events for pages that are unaware of input events,
* to provide web compatibility for pages that depend on key events.
* Our dummy key events have 0 as the keycode.
*/
void
GeckoEditableSupport::SendIMEDummyKeyEvent(nsIWidget* aWidget, EventMessage msg)
@ -677,12 +678,7 @@ GeckoEditableSupport::SendIMEDummyKeyEvent(nsIWidget* aWidget, EventMessage msg)
WidgetKeyboardEvent event(true, msg, aWidget);
event.mTime = PR_Now() / 1000;
// TODO: If we can know scan code of the key event which caused replacing
// composition string, we should set mCodeNameIndex here. Then,
// we should rename this method because it becomes not a "dummy"
// keyboard event.
event.mKeyCode = NS_VK_PROCESSKEY;
event.mKeyNameIndex = KEY_NAME_INDEX_Process;
MOZ_ASSERT(event.mKeyCode == 0);
NS_ENSURE_SUCCESS_VOID(BeginInputTransaction(mDispatcher));
mDispatcher->DispatchKeyboardEvent(msg, event, status);
}
@ -1031,19 +1027,12 @@ GeckoEditableSupport::OnImeReplaceText(int32_t aStart, int32_t aEnd,
AddIMETextChange(dummyChange);
}
// Until fixing bug 354358 in release channel, we should always ignore
// "intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition"
// pref in Nightly and early Beta for testing new regressions.
#ifndef EARLY_BETA_OR_EARLIER
if (mInputContext.mMayBeIMEUnaware) {
#endif // #ifndef EARLY_BETA_OR_EARLIER
SendIMEDummyKeyEvent(widget, eKeyDown);
if (!mDispatcher || widget->Destroyed()) {
return;
}
#ifndef EARLY_BETA_OR_EARLIER
}
#endif // #ifndef EARLY_BETA_OR_EARLIER
if (composing) {
mDispatcher->SetPendingComposition(string, mIMERanges);
@ -1057,18 +1046,10 @@ GeckoEditableSupport::OnImeReplaceText(int32_t aStart, int32_t aEnd,
return;
}
// XXX This works fine if user inputs with virtual keyboard. However,
// if user inputs with hardware keyboard, keyup event may come later.
// So, perhaps, we need to record actual keyboard events before
// this replacement of composition string.
#ifndef EARLY_BETA_OR_EARLIER
if (mInputContext.mMayBeIMEUnaware) {
#endif // #ifndef EARLY_BETA_OR_EARLIER
SendIMEDummyKeyEvent(widget, eKeyUp);
// Widget may be destroyed after dispatching the above event.
#ifndef EARLY_BETA_OR_EARLIER
}
#endif // #ifndef EARLY_BETA_OR_EARLIER
}
void

View File

@ -243,9 +243,6 @@ public:
* dispatch a Gecko key event.
* @param aKeyEvent The result -- a Gecko key event initialized
* from the native key event.
* @param aIsProcessedByIME true if aNativeKeyEvent has been handled
* by IME (but except if the composition was
* started with dead key).
* @param aInsertString If caller expects that the event will cause
* a character to be input (say in an editor),
* the caller should set this. Otherwise,
@ -254,7 +251,6 @@ public:
* characters of aNativeKeyEvent.
*/
void InitKeyEvent(NSEvent *aNativeKeyEvent, WidgetKeyboardEvent& aKeyEvent,
bool aIsProcessedByIME,
const nsAString *aInsertString = nullptr);
/**
@ -307,15 +303,6 @@ public:
static CodeNameIndex ComputeGeckoCodeNameIndex(UInt32 aNativeKeyCode,
UInt32 aKbType);
/**
* TranslateToChar() checks if aNativeKeyEvent is a dead key.
*
* @param aNativeKeyEvent A native key event.
* @return Returns true if the key event is a dead key
* event. Otherwise, false.
*/
bool IsDeadKey(NSEvent* aNativeKeyEvent);
protected:
/**
* TranslateToString() computes the inputted text from the native keyCode,
@ -356,7 +343,7 @@ protected:
* @param aKbType A native Keyboard Type value. Typically,
* this is a result of ::LMGetKbdType().
* @return Returns true if the key with specified
* modifier state is a dead key. Otherwise,
* modifier state isa dead key. Otherwise,
* false.
*/
bool IsDeadKey(UInt32 aKeyCode, UInt32 aModifiers, UInt32 aKbType);
@ -446,9 +433,6 @@ public:
* dispatch a Gecko key event.
* @param aKeyEvent The result -- a Gecko key event initialized
* from the native key event.
* @param aIsProcessedByIME true if aNativeKeyEvent has been handled
* by IME (but except if the composition was
* started with dead key).
* @param aInsertString If caller expects that the event will cause
* a character to be input (say in an editor),
* the caller should set this. Otherwise,
@ -457,7 +441,6 @@ public:
* characters of aNativeKeyEvent.
*/
void InitKeyEvent(NSEvent *aNativeKeyEvent, WidgetKeyboardEvent& aKeyEvent,
bool aIsProcessedByIME,
const nsAString *aInsertString = nullptr);
/**
@ -569,8 +552,6 @@ protected:
// Unique id associated with a keydown / keypress event. It's ok if this
// wraps over long periods.
uint32_t mUniqueId;
// Whether keydown event was dispatched for mKeyEvent.
bool mKeyDownDispatched;
// Whether keydown event was consumed by web contents or chrome contents.
bool mKeyDownHandled;
// Whether keypress event was dispatched for mKeyEvent.
@ -623,7 +604,6 @@ protected:
}
mInsertString = nullptr;
mInsertedString.Truncate();
mKeyDownDispatched = false;
mKeyDownHandled = false;
mKeyPressDispatched = false;
mKeyPressHandled = false;
@ -637,11 +617,6 @@ protected:
mCompositionDispatched;
}
bool CanDispatchKeyDownEvent() const
{
return !mKeyDownDispatched;
}
bool CanDispatchKeyPressEvent() const
{
return !mKeyPressDispatched && !IsDefaultPrevented();
@ -790,8 +765,7 @@ protected:
}
void InitKeyEvent(TextInputHandlerBase* aHandler,
WidgetKeyboardEvent& aKeyEvent,
bool aIsProcessedByIME);
WidgetKeyboardEvent& aKeyEvent);
/**
* GetUnhandledString() returns characters of the event which have not been
@ -1085,7 +1059,6 @@ public:
NSRange MarkedRange();
bool IsIMEComposing() { return mIsIMEComposing; }
bool IsDeadKeyComposing() { return mIsDeadKeyComposing; }
bool IsIMEOpened();
bool IsIMEEnabled() { return mIsIMEEnabled; }
bool IsASCIICapableOnly() { return mIsASCIICapableOnly; }
@ -1139,19 +1112,6 @@ protected:
void InsertTextAsCommittingComposition(NSAttributedString* aAttrString,
NSRange* aReplacementRange);
/**
* MaybeDispatchCurrentKeydownEvent() dispatches eKeyDown event for current
* key event. If eKeyDown for current key event has already been dispatched,
* this does nothing.
*
* @param aIsProcessedByIME true if current key event is handled by IME.
* @return true if the caller can continue to handle
* current key event. Otherwise, false. E.g.,
* focus is moved, the widget has been destroyed
* or something.
*/
bool MaybeDispatchCurrentKeydownEvent(bool aIsProcessedByIME);
private:
// If mIsIMEComposing is true, the composition string is stored here.
NSString* mIMECompositionString;
@ -1165,9 +1125,6 @@ private:
mozilla::WritingMode mWritingMode;
bool mIsIMEComposing;
// If the composition started with dead key, mIsDeadKeyComposing is set to
// true.
bool mIsDeadKeyComposing;
bool mIsIMEEnabled;
bool mIsASCIICapableOnly;
bool mIgnoreIMECommit;

View File

@ -399,84 +399,6 @@ TISInputSourceWrapper::TranslateToChar(UInt32 aKeyCode, UInt32 aModifiers,
return static_cast<uint32_t>(str.CharAt(0));
}
bool
TISInputSourceWrapper::IsDeadKey(NSEvent* aNativeKeyEvent)
{
if ([[aNativeKeyEvent characters] length]) {
return false;
}
// Assmue that if control key or command key is pressed, it's not a dead key.
NSUInteger cocoaState = [aNativeKeyEvent modifierFlags];
if (cocoaState & (NSControlKeyMask | NSCommandKeyMask)) {
return false;
}
UInt32 nativeKeyCode = [aNativeKeyEvent keyCode];
switch (nativeKeyCode) {
case kVK_ANSI_A:
case kVK_ANSI_B:
case kVK_ANSI_C:
case kVK_ANSI_D:
case kVK_ANSI_E:
case kVK_ANSI_F:
case kVK_ANSI_G:
case kVK_ANSI_H:
case kVK_ANSI_I:
case kVK_ANSI_J:
case kVK_ANSI_K:
case kVK_ANSI_L:
case kVK_ANSI_M:
case kVK_ANSI_N:
case kVK_ANSI_O:
case kVK_ANSI_P:
case kVK_ANSI_Q:
case kVK_ANSI_R:
case kVK_ANSI_S:
case kVK_ANSI_T:
case kVK_ANSI_U:
case kVK_ANSI_V:
case kVK_ANSI_W:
case kVK_ANSI_X:
case kVK_ANSI_Y:
case kVK_ANSI_Z:
case kVK_ANSI_1:
case kVK_ANSI_2:
case kVK_ANSI_3:
case kVK_ANSI_4:
case kVK_ANSI_5:
case kVK_ANSI_6:
case kVK_ANSI_7:
case kVK_ANSI_8:
case kVK_ANSI_9:
case kVK_ANSI_0:
case kVK_ANSI_Equal:
case kVK_ANSI_Minus:
case kVK_ANSI_RightBracket:
case kVK_ANSI_LeftBracket:
case kVK_ANSI_Quote:
case kVK_ANSI_Semicolon:
case kVK_ANSI_Backslash:
case kVK_ANSI_Comma:
case kVK_ANSI_Slash:
case kVK_ANSI_Period:
case kVK_ANSI_Grave:
case kVK_JIS_Yen:
case kVK_JIS_Underscore:
break;
default:
// Let's assume that dead key can be only a printable key in standard
// position.
return false;
}
// If TranslateToChar() returns non-zero value, that means that
// the key may input a character with different dead key state.
UInt32 kbType = GetKbdType();
UInt32 carbonState = nsCocoaUtils::ConvertToCarbonModifier(cocoaState);
return IsDeadKey(nativeKeyCode, carbonState, kbType);
}
bool
TISInputSourceWrapper::IsDeadKey(UInt32 aKeyCode,
UInt32 aModifiers,
@ -984,25 +906,17 @@ TISInputSourceWrapper::ComputeInsertStringForCharCode(
void
TISInputSourceWrapper::InitKeyEvent(NSEvent *aNativeKeyEvent,
WidgetKeyboardEvent& aKeyEvent,
bool aIsProcessedByIME,
const nsAString *aInsertString)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
MOZ_ASSERT(!aIsProcessedByIME || aKeyEvent.mMessage != eKeyPress,
"eKeyPress event should not be marked as proccessed by IME");
MOZ_LOG(gLog, LogLevel::Info,
("%p TISInputSourceWrapper::InitKeyEvent, aNativeKeyEvent=%p, "
"aKeyEvent.mMessage=%s, aProcessedByIME=%s, aInsertString=%p, "
"IsOpenedIMEMode()=%s",
this, aNativeKeyEvent, GetGeckoKeyEventType(aKeyEvent),
TrueOrFalse(aIsProcessedByIME), aInsertString,
"aKeyEvent.mMessage=%s, aInsertString=%p, IsOpenedIMEMode()=%s",
this, aNativeKeyEvent, GetGeckoKeyEventType(aKeyEvent), aInsertString,
TrueOrFalse(IsOpenedIMEMode())));
if (NS_WARN_IF(!aNativeKeyEvent)) {
return;
}
NS_ENSURE_TRUE(aNativeKeyEvent, );
nsCocoaUtils::InitInputEvent(aKeyEvent, aNativeKeyEvent);
@ -1031,18 +945,8 @@ TISInputSourceWrapper::InitKeyEvent(NSEvent *aNativeKeyEvent,
UInt32 kbType = GetKbdType();
UInt32 nativeKeyCode = [aNativeKeyEvent keyCode];
// macOS handles dead key as IME. If the key is first key press of dead
// key, we should use KEY_NAME_INDEX_Dead for first (dead) key event.
// So, if aIsProcessedByIME is true, it may be dead key. Let's check
// if current key event is a dead key's keydown event.
bool isProcessedByIME =
aIsProcessedByIME &&
!TISInputSourceWrapper::CurrentInputSource().IsDeadKey(aNativeKeyEvent);
aKeyEvent.mKeyCode =
isProcessedByIME ?
NS_VK_PROCESSKEY :
ComputeGeckoKeyCode(nativeKeyCode, kbType, aKeyEvent.IsMeta());
ComputeGeckoKeyCode(nativeKeyCode, kbType, aKeyEvent.IsMeta());
switch (nativeKeyCode) {
case kVK_Command:
@ -1095,9 +999,7 @@ TISInputSourceWrapper::InitKeyEvent(NSEvent *aNativeKeyEvent,
this, OnOrOff(aKeyEvent.IsShift()), OnOrOff(aKeyEvent.IsControl()),
OnOrOff(aKeyEvent.IsAlt()), OnOrOff(aKeyEvent.IsMeta())));
if (isProcessedByIME) {
aKeyEvent.mKeyNameIndex = KEY_NAME_INDEX_Process;
} else if (IsPrintableKeyEvent(aNativeKeyEvent)) {
if (IsPrintableKeyEvent(aNativeKeyEvent)) {
aKeyEvent.mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
// If insertText calls this method, let's use the string.
if (aInsertString && !aInsertString->IsEmpty() &&
@ -1726,7 +1628,7 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent,
}
WidgetKeyboardEvent imeEvent(true, eKeyDown, widget);
currentKeyEvent->InitKeyEvent(this, imeEvent, false);
currentKeyEvent->InitKeyEvent(this, imeEvent);
imeEvent.mPluginTextEventString.Assign(committed);
nsEventStatus status = nsEventStatus_eIgnore;
mDispatcher->DispatchKeyboardEvent(eKeyDown, imeEvent, status,
@ -1735,18 +1637,50 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent,
return true;
}
RefPtr<TextInputHandler> kungFuDeathGrip(this);
NSResponder* firstResponder = [[mView window] firstResponder];
// When we're already in a composition, we need always to mark the eKeyDown
// event as "processed by IME". So, let's dispatch eKeyDown event here in
// such case.
if (IsIMEComposing() && !MaybeDispatchCurrentKeydownEvent(true)) {
MOZ_LOG(gLog, LogLevel::Info,
("%p IMEInputHandler::HandleKeyDownEvent, eKeyDown caused focus move or "
"something and canceling the composition", this));
nsresult rv = mDispatcher->BeginNativeInputTransaction();
if (NS_WARN_IF(NS_FAILED(rv))) {
MOZ_LOG(gLog, LogLevel::Error,
("%p IMEInputHandler::HandleKeyDownEvent, "
"FAILED, due to BeginNativeInputTransaction() failure "
"at dispatching keydown for ordinal cases", this));
return false;
}
WidgetKeyboardEvent keydownEvent(true, eKeyDown, widget);
currentKeyEvent->InitKeyEvent(this, keydownEvent);
nsEventStatus status = nsEventStatus_eIgnore;
mDispatcher->DispatchKeyboardEvent(eKeyDown, keydownEvent, status,
currentKeyEvent);
currentKeyEvent->mKeyDownHandled =
(status == nsEventStatus_eConsumeNoDefault);
if (Destroyed()) {
MOZ_LOG(gLog, LogLevel::Info,
("%p TextInputHandler::HandleKeyDownEvent, "
"widget was destroyed by keydown event", this));
return currentKeyEvent->IsDefaultPrevented();
}
// The key down event may have shifted the focus, in which
// case we should not fire the key press.
// XXX This is a special code only on Cocoa widget, why is this needed?
if (firstResponder != [[mView window] firstResponder]) {
MOZ_LOG(gLog, LogLevel::Info,
("%p TextInputHandler::HandleKeyDownEvent, "
"view lost focus by keydown event", this));
return currentKeyEvent->IsDefaultPrevented();
}
if (currentKeyEvent->IsDefaultPrevented()) {
MOZ_LOG(gLog, LogLevel::Info,
("%p TextInputHandler::HandleKeyDownEvent, "
"keydown event's default is prevented", this));
return true;
}
// Let Cocoa interpret the key events, caching IsIMEComposing first.
bool wasComposing = IsIMEComposing();
bool interpretKeyEventsCalled = false;
@ -1776,33 +1710,9 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent,
"IsIMEComposing()=%s",
this, TrueOrFalse(wasComposing), TrueOrFalse(IsIMEComposing())));
if (currentKeyEvent->CanDispatchKeyDownEvent()) {
// Dispatch eKeyDown event if nobody has dispatched it yet.
// NOTE: Although reaching here means that the native keydown event may
// not be handled by IME. However, we cannot know if it is.
// For example, Japanese IME of Apple shows candidate window for
// typing window. They, you can switch the sort order with Tab key.
// However, when you choose "Symbol" of the sort order, there may
// be no candiate words. In this case, IME handles the Tab key
// actually, but we cannot know it because composition string is
// not updated. So, let's mark eKeyDown event as "processed by IME"
// when there is composition string. This is same as Chrome.
MOZ_LOG(gLog, LogLevel::Info,
("%p TextInputHandler::HandleKeyDownEvent, trying to dispatch eKeyDown "
"event since it's not yet dispatched",
this));
if (!MaybeDispatchCurrentKeydownEvent(IsIMEComposing())) {
return true; // treat the eKeydDown event as consumed.
}
MOZ_LOG(gLog, LogLevel::Info,
("%p TextInputHandler::HandleKeyDownEvent, eKeyDown event has been "
"dispatched",
this));
}
if (currentKeyEvent->CanDispatchKeyPressEvent() &&
!wasComposing && !IsIMEComposing()) {
nsresult rv = mDispatcher->BeginNativeInputTransaction();
rv = mDispatcher->BeginNativeInputTransaction();
if (NS_WARN_IF(NS_FAILED(rv))) {
MOZ_LOG(gLog, LogLevel::Error,
("%p IMEInputHandler::HandleKeyDownEvent, "
@ -1812,7 +1722,7 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent,
}
WidgetKeyboardEvent keypressEvent(true, eKeyPress, widget);
currentKeyEvent->InitKeyEvent(this, keypressEvent, false);
currentKeyEvent->InitKeyEvent(this, keypressEvent);
// If we called interpretKeyEvents and this isn't normal character input
// then IME probably ate the event for some reason. We do not want to
@ -1827,11 +1737,6 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent,
// our default action for this key.
if (!(interpretKeyEventsCalled &&
IsNormalCharInputtingEvent(keypressEvent))) {
MOZ_LOG(gLog, LogLevel::Info,
("%p TextInputHandler::HandleKeyDownEvent, trying to dispatch "
"eKeyPress event since it's not yet dispatched",
this));
nsEventStatus status = nsEventStatus_eIgnore;
currentKeyEvent->mKeyPressDispatched =
mDispatcher->MaybeDispatchKeypressEvents(keypressEvent, status,
currentKeyEvent);
@ -1839,8 +1744,7 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent,
(status == nsEventStatus_eConsumeNoDefault);
currentKeyEvent->mKeyPressDispatched = true;
MOZ_LOG(gLog, LogLevel::Info,
("%p TextInputHandler::HandleKeyDownEvent, eKeyPress event has been "
"dispatched",
("%p TextInputHandler::HandleKeyDownEvent, keypress event dispatched",
this));
}
}
@ -1894,10 +1798,8 @@ TextInputHandler::HandleKeyUpEvent(NSEvent* aNativeEvent)
return;
}
// Neither Chrome for macOS nor Safari marks "keyup" event as "processed by
// IME" even during composition. So, let's follow this behavior.
WidgetKeyboardEvent keyupEvent(true, eKeyUp, mWidget);
InitKeyEvent(aNativeEvent, keyupEvent, false);
InitKeyEvent(aNativeEvent, keyupEvent);
KeyEventState currentKeyEvent(aNativeEvent);
nsEventStatus status = nsEventStatus_eIgnore;
@ -2241,7 +2143,7 @@ TextInputHandler::DispatchKeyEventForFlagsChanged(NSEvent* aNativeEvent,
GetKeyNameForNativeKeyCode([aNativeEvent keyCode]), [aNativeEvent keyCode],
TrueOrFalse(aDispatchKeyDown), TrueOrFalse(IsIMEComposing())));
if ([aNativeEvent type] != NSFlagsChanged) {
if ([aNativeEvent type] != NSFlagsChanged || IsIMEComposing()) {
return;
}
@ -2255,11 +2157,9 @@ TextInputHandler::DispatchKeyEventForFlagsChanged(NSEvent* aNativeEvent,
EventMessage message = aDispatchKeyDown ? eKeyDown : eKeyUp;
// Fire a key event for the modifier key. Note that even if modifier key
// is pressed during composition, we shouldn't mark the keyboard event as
// "processed by IME" since neither Chrome for macOS nor Safari does it.
// Fire a key event.
WidgetKeyboardEvent keyEvent(true, message, mWidget);
InitKeyEvent(aNativeEvent, keyEvent, false);
InitKeyEvent(aNativeEvent, keyEvent);
// Attach a plugin event, in case keyEvent gets dispatched to a plugin. Only
// one field is needed -- the type. The other fields can be constructed as
@ -2295,16 +2195,13 @@ TextInputHandler::InsertText(NSAttributedString* aAttrString,
("%p TextInputHandler::InsertText, aAttrString=\"%s\", "
"aReplacementRange=%p { location=%lu, length=%lu }, "
"IsIMEComposing()=%s, "
"keyevent=%p, keydownDispatched=%s, "
"keydownHandled=%s, keypressDispatched=%s, "
"keyevent=%p, keydownHandled=%s, keypressDispatched=%s, "
"causedOtherKeyEvents=%s, compositionDispatched=%s",
this, GetCharacters([aAttrString string]), aReplacementRange,
static_cast<unsigned long>(aReplacementRange ? aReplacementRange->location : 0),
static_cast<unsigned long>(aReplacementRange ? aReplacementRange->length : 0),
TrueOrFalse(IsIMEComposing()),
currentKeyEvent ? currentKeyEvent->mKeyEvent : nullptr,
currentKeyEvent ?
TrueOrFalse(currentKeyEvent->mKeyDownDispatched) : "N/A",
currentKeyEvent ?
TrueOrFalse(currentKeyEvent->mKeyDownHandled) : "N/A",
currentKeyEvent ?
@ -2356,21 +2253,8 @@ TextInputHandler::InsertText(NSAttributedString* aAttrString,
if (!currentKeyEvent) {
return;
}
// When current keydown event causes this empty text input, let's
// dispatch eKeyDown event before any other events. Note that if we're
// in a composition, we've already dispatched eKeyDown event from
// TextInputHandler::HandleKeyDownEvent().
// XXX Should we mark this eKeyDown event as "processed by IME"?
RefPtr<TextInputHandler> kungFuDeathGrip(this);
if (!IsIMEComposing() && !MaybeDispatchCurrentKeydownEvent(false)) {
MOZ_LOG(gLog, LogLevel::Info,
("%p IMEInputHandler::InsertText, eKeyDown caused focus move or "
"something and canceling the composition", this));
return;
}
// Delete the selected range.
RefPtr<TextInputHandler> kungFuDeathGrip(this);
WidgetContentCommandEvent deleteCommandEvent(true, eContentCommandDelete,
mWidget);
DispatchEvent(deleteCommandEvent);
@ -2419,23 +2303,13 @@ TextInputHandler::InsertText(NSAttributedString* aAttrString,
return;
}
// This is the normal path to input a character when you press a key.
// Let's dispatch eKeyDown event now.
RefPtr<TextInputHandler> kungFuDeathGrip(this);
if (!MaybeDispatchCurrentKeydownEvent(false)) {
MOZ_LOG(gLog, LogLevel::Info,
("%p IMEInputHandler::InsertText, eKeyDown caused focus move or "
"something and canceling the composition", this));
return;
}
// XXX Shouldn't we hold mDispatcher instead of mWidget?
RefPtr<nsChildView> widget(mWidget);
nsresult rv = mDispatcher->BeginNativeInputTransaction();
if (NS_WARN_IF(NS_FAILED(rv))) {
MOZ_LOG(gLog, LogLevel::Error,
("%p IMEInputHandler::InsertText, "
"FAILED, due to BeginNativeInputTransaction() failure", this));
MOZ_LOG(gLog, LogLevel::Error,
("%p IMEInputHandler::HandleKeyUpEvent, "
"FAILED, due to BeginNativeInputTransaction() failure", this));
return;
}
@ -2451,7 +2325,7 @@ TextInputHandler::InsertText(NSAttributedString* aAttrString,
// the input string.
if (currentKeyEvent) {
currentKeyEvent->InitKeyEvent(this, keypressEvent, false);
currentKeyEvent->InitKeyEvent(this, keypressEvent);
} else {
nsCocoaUtils::InitInputEvent(keypressEvent, static_cast<NSEvent*>(nullptr));
keypressEvent.mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
@ -2517,18 +2391,6 @@ TextInputHandler::HandleCommand(Command aCommand)
return false;
}
// When current keydown event causes this command, let's dispatch
// eKeyDown event before any other events. Note that if we're in a
// composition, we've already dispatched eKeyDown event from
// TextInputHandler::HandleKeyDownEvent().
RefPtr<TextInputHandler> kungFuDeathGrip(this);
if (!IsIMEComposing() && !MaybeDispatchCurrentKeydownEvent(false)) {
MOZ_LOG(gLog, LogLevel::Info,
("%p IMEInputHandler::SetMarkedText, eKeyDown caused focus move or "
"something and canceling the composition", this));
return false;
}
// If it's in composition, we cannot dispatch keypress event.
// Therefore, we should use different approach or give up to handle
// the command.
@ -2625,7 +2487,7 @@ TextInputHandler::HandleCommand(Command aCommand)
if (!dispatchFakeKeyPress) {
// If we're acutally handling a key press, we should dispatch
// the keypress event as-is.
currentKeyEvent->InitKeyEvent(this, keypressEvent, false);
currentKeyEvent->InitKeyEvent(this, keypressEvent);
} else {
// Otherwise, we should dispatch "fake" keypress event.
// However, for making it possible to compute edit commands, we need to
@ -2891,15 +2753,11 @@ TextInputHandler::DoCommandBySelector(const char* aSelector)
MOZ_LOG(gLog, LogLevel::Info,
("%p TextInputHandler::DoCommandBySelector, aSelector=\"%s\", "
"Destroyed()=%s, keydownDispatched=%s, keydownHandled=%s, "
"keypressDispatched=%s, keypressHandled=%s, causedOtherKeyEvents=%s",
"Destroyed()=%s, keydownHandled=%s, keypressHandled=%s, "
"causedOtherKeyEvents=%s",
this, aSelector ? aSelector : "", TrueOrFalse(Destroyed()),
currentKeyEvent ?
TrueOrFalse(currentKeyEvent->mKeyDownDispatched) : "N/A",
currentKeyEvent ?
TrueOrFalse(currentKeyEvent->mKeyDownHandled) : "N/A",
currentKeyEvent ?
TrueOrFalse(currentKeyEvent->mKeyPressDispatched) : "N/A",
currentKeyEvent ?
TrueOrFalse(currentKeyEvent->mKeyPressHandled) : "N/A",
currentKeyEvent ?
@ -2911,18 +2769,6 @@ TextInputHandler::DoCommandBySelector(const char* aSelector)
return Destroyed();
}
// When current keydown event causes this command, let's dispatch
// eKeyDown event before any other events. Note that if we're in a
// composition, we've already dispatched eKeyDown event from
// TextInputHandler::HandleKeyDownEvent().
RefPtr<TextInputHandler> kungFuDeathGrip(this);
if (!IsIMEComposing() && !MaybeDispatchCurrentKeydownEvent(false)) {
MOZ_LOG(gLog, LogLevel::Info,
("%p IMEInputHandler::SetMarkedText, eKeyDown caused focus move or "
"something and canceling the composition", this));
return true;
}
// If the key operation causes this command, should dispatch a keypress
// event.
// XXX This must be worng. Even if this command is caused by the key
@ -2940,7 +2786,7 @@ TextInputHandler::DoCommandBySelector(const char* aSelector)
}
WidgetKeyboardEvent keypressEvent(true, eKeyPress, widget);
currentKeyEvent->InitKeyEvent(this, keypressEvent, false);
currentKeyEvent->InitKeyEvent(this, keypressEvent);
nsEventStatus status = nsEventStatus_eIgnore;
currentKeyEvent->mKeyPressDispatched =
@ -3553,11 +3399,6 @@ IMEInputHandler::DispatchCompositionStartEvent()
NS_ASSERTION(!mIsIMEComposing, "There is a composition already");
mIsIMEComposing = true;
KeyEventState* currentKeyEvent = GetCurrentKeyEvent();
mIsDeadKeyComposing =
currentKeyEvent && currentKeyEvent->mKeyEvent &&
TISInputSourceWrapper::CurrentInputSource().
IsDeadKey(currentKeyEvent->mKeyEvent);
nsEventStatus status;
rv = mDispatcher->StartComposition(status);
@ -3708,7 +3549,7 @@ IMEInputHandler::DispatchCompositionCommitEvent(const nsAString* aCommitString)
}
}
mIsIMEComposing = mIsDeadKeyComposing = false;
mIsIMEComposing = false;
mIMECompositionStart = UINT32_MAX;
if (mIMECompositionString) {
[mIMECompositionString release];
@ -3727,89 +3568,6 @@ IMEInputHandler::DispatchCompositionCommitEvent(const nsAString* aCommitString)
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
}
bool
IMEInputHandler::MaybeDispatchCurrentKeydownEvent(bool aIsProcessedByIME)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
if (Destroyed()) {
return false;
}
MOZ_ASSERT(mWidget);
KeyEventState* currentKeyEvent = GetCurrentKeyEvent();
if (!currentKeyEvent ||
!currentKeyEvent->CanDispatchKeyDownEvent()) {
return true;
}
NSEvent* nativeEvent = currentKeyEvent->mKeyEvent;
if (NS_WARN_IF(!nativeEvent) ||
[nativeEvent type] != NSKeyDown) {
return true;
}
MOZ_LOG(gLog, LogLevel::Info,
("%p IMEInputHandler::MaybeDispatchKeydownEvent, aIsProcessedByIME=%s "
"currentKeyEvent={ mKeyEvent(%p)={ type=%s, keyCode=%s (0x%X) } }, "
"aIsProcesedBy=%s, IsDeadKeyComposing()=%s",
this, TrueOrFalse(aIsProcessedByIME), nativeEvent,
GetNativeKeyEventType(nativeEvent),
GetKeyNameForNativeKeyCode([nativeEvent keyCode]), [nativeEvent keyCode],
TrueOrFalse(IsIMEComposing()), TrueOrFalse(IsDeadKeyComposing())));
RefPtr<IMEInputHandler> kungFuDeathGrip(this);
RefPtr<TextEventDispatcher> dispatcher(mDispatcher);
nsresult rv = dispatcher->BeginNativeInputTransaction();
if (NS_WARN_IF(NS_FAILED(rv))) {
MOZ_LOG(gLog, LogLevel::Error,
("%p IMEInputHandler::DispatchKeyEventForFlagsChanged, "
"FAILED, due to BeginNativeInputTransaction() failure", this));
return false;
}
NSResponder* firstResponder = [[mView window] firstResponder];
// Mark currentKeyEvent as "dispatched eKeyDown event" and actually do it.
currentKeyEvent->mKeyDownDispatched = true;
RefPtr<nsChildView> widget(mWidget);
WidgetKeyboardEvent keydownEvent(true, eKeyDown, widget);
// Don't mark the eKeyDown event as "processed by IME" if the composition
// is started with dead key.
currentKeyEvent->InitKeyEvent(this, keydownEvent,
aIsProcessedByIME && !IsDeadKeyComposing());
nsEventStatus status = nsEventStatus_eIgnore;
dispatcher->DispatchKeyboardEvent(eKeyDown, keydownEvent, status,
currentKeyEvent);
currentKeyEvent->mKeyDownHandled =
(status == nsEventStatus_eConsumeNoDefault);
if (Destroyed()) {
MOZ_LOG(gLog, LogLevel::Info,
("%p IMEInputHandler::MaybeDispatchKeydownEvent, "
"widget was destroyed by keydown event", this));
return false;
}
// The key down event may have shifted the focus, in which case, we should
// not continue to handle current key sequence and let's commit current
// composition.
if (firstResponder != [[mView window] firstResponder]) {
MOZ_LOG(gLog, LogLevel::Info,
("%p IMEInputHandler::MaybeDispatchKeydownEvent, "
"view lost focus by keydown event", this));
CommitIMEComposition();
return false;
}
return true;
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
}
void
IMEInputHandler::InsertTextAsCommittingComposition(
NSAttributedString* aAttrString,
@ -3838,22 +3596,6 @@ IMEInputHandler::InsertTextAsCommittingComposition(
return;
}
// When current keydown event causes this text input, let's dispatch
// eKeyDown event before any other events. Note that if we're in a
// composition, we've already dispatched eKeyDown event from
// TextInputHandler::HandleKeyDownEvent().
// XXX Should we mark the eKeyDown event as "processed by IME"?
// However, if the key causes two or more Unicode characters as
// UTF-16 string, this is used. So, perhaps, we need to improve
// HandleKeyDownEvent() before do that.
RefPtr<IMEInputHandler> kungFuDeathGrip(this);
if (!IsIMEComposing() && !MaybeDispatchCurrentKeydownEvent(false)) {
MOZ_LOG(gLog, LogLevel::Info,
("%p IMEInputHandler::InsertTextAsCommittingComposition, eKeyDown "
"caused focus move or something and canceling the composition", this));
return;
}
// First, commit current composition with the latest composition string if the
// replacement range is different from marked range.
if (IsIMEComposing() && aReplacementRange &&
@ -3868,6 +3610,8 @@ IMEInputHandler::InsertTextAsCommittingComposition(
}
}
RefPtr<IMEInputHandler> kungFuDeathGrip(this);
nsString str;
nsCocoaUtils::GetStringForNSString([aAttrString string], str);
@ -3914,8 +3658,7 @@ IMEInputHandler::SetMarkedText(NSAttributedString* aAttrString,
"aReplacementRange=%p { location=%lu, length=%lu }, "
"Destroyed()=%s, IsIMEComposing()=%s, "
"mMarkedRange={ location=%lu, length=%lu }, keyevent=%p, "
"keydownDispatched=%s, keydownHandled=%s, "
"keypressDispatched=%s, causedOtherKeyEvents=%s, "
"keydownHandled=%s, keypressDispatched=%s, causedOtherKeyEvents=%s, "
"compositionDispatched=%s",
this, GetCharacters([aAttrString string]),
static_cast<unsigned long>(aSelectedRange.location),
@ -3926,8 +3669,6 @@ IMEInputHandler::SetMarkedText(NSAttributedString* aAttrString,
static_cast<unsigned long>(mMarkedRange.location),
static_cast<unsigned long>(mMarkedRange.length),
currentKeyEvent ? currentKeyEvent->mKeyEvent : nullptr,
currentKeyEvent ?
TrueOrFalse(currentKeyEvent->mKeyDownDispatched) : "N/A",
currentKeyEvent ?
TrueOrFalse(currentKeyEvent->mKeyDownHandled) : "N/A",
currentKeyEvent ?
@ -3937,32 +3678,19 @@ IMEInputHandler::SetMarkedText(NSAttributedString* aAttrString,
currentKeyEvent ?
TrueOrFalse(currentKeyEvent->mCompositionDispatched) : "N/A"));
RefPtr<IMEInputHandler> kungFuDeathGrip(this);
// If SetMarkedText() is called during handling a key press, that means that
// the key event caused this composition. So, keypress event shouldn't
// be dispatched later, let's mark the key event causing composition event.
if (currentKeyEvent) {
currentKeyEvent->mCompositionDispatched = true;
// When current keydown event causes this text input, let's dispatch
// eKeyDown event before any other events. Note that if we're in a
// composition, we've already dispatched eKeyDown event from
// TextInputHandler::HandleKeyDownEvent(). On the other hand, if we're
// not in composition, the key event starts new composition. So, we
// need to mark the eKeyDown event as "processed by IME".
if (!IsIMEComposing() && !MaybeDispatchCurrentKeydownEvent(true)) {
MOZ_LOG(gLog, LogLevel::Info,
("%p IMEInputHandler::SetMarkedText, eKeyDown caused focus move or "
"something and canceling the composition", this));
return;
}
}
if (Destroyed()) {
return;
}
RefPtr<IMEInputHandler> kungFuDeathGrip(this);
// First, commit current composition with the latest composition string if the
// replacement range is different from marked range.
if (IsIMEComposing() && aReplacementRange &&
@ -4419,7 +4147,6 @@ IMEInputHandler::IMEInputHandler(nsChildView* aWidget,
, mIMECompositionString(nullptr)
, mIMECompositionStart(UINT32_MAX)
, mIsIMEComposing(false)
, mIsDeadKeyComposing(false)
, mIsIMEEnabled(true)
, mIsASCIICapableOnly(false)
, mIgnoreIMECommit(false)
@ -4578,15 +4305,13 @@ IMEInputHandler::CommitIMEComposition()
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
if (!IsIMEComposing())
return;
MOZ_LOG(gLog, LogLevel::Info,
("%p IMEInputHandler::CommitIMEComposition, mIMECompositionString=%s",
this, GetCharacters(mIMECompositionString)));
// If this is called before dispatching eCompositionStart, IsIMEComposing()
// returns false. Even in such case, we need to commit composition *in*
// IME if this is called by preceding eKeyDown event of eCompositionStart.
// So, we need to call KillIMEComposition() even when IsIMEComposing()
// returns false.
KillIMEComposition();
if (!IsIMEComposing())
@ -4860,7 +4585,6 @@ TextInputHandlerBase::DispatchEvent(WidgetGUIEvent& aEvent)
void
TextInputHandlerBase::InitKeyEvent(NSEvent *aNativeKeyEvent,
WidgetKeyboardEvent& aKeyEvent,
bool aIsProcessedByIME,
const nsAString* aInsertString)
{
NS_ASSERTION(aNativeKeyEvent, "aNativeKeyEvent must not be NULL");
@ -4868,12 +4592,11 @@ TextInputHandlerBase::InitKeyEvent(NSEvent *aNativeKeyEvent,
if (mKeyboardOverride.mOverrideEnabled) {
TISInputSourceWrapper tis;
tis.InitByLayoutID(mKeyboardOverride.mKeyboardLayout, true);
tis.InitKeyEvent(aNativeKeyEvent, aKeyEvent, aIsProcessedByIME,
aInsertString);
tis.InitKeyEvent(aNativeKeyEvent, aKeyEvent, aInsertString);
return;
}
TISInputSourceWrapper::CurrentInputSource().
InitKeyEvent(aNativeKeyEvent, aKeyEvent, aIsProcessedByIME, aInsertString);
InitKeyEvent(aNativeKeyEvent, aKeyEvent, aInsertString);
}
nsresult
@ -5166,8 +4889,7 @@ TextInputHandlerBase::EnsureSecureEventInputDisabled()
void
TextInputHandlerBase::KeyEventState::InitKeyEvent(
TextInputHandlerBase* aHandler,
WidgetKeyboardEvent& aKeyEvent,
bool aIsProcessedByIME)
WidgetKeyboardEvent& aKeyEvent)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
@ -5197,8 +4919,7 @@ TextInputHandlerBase::KeyEventState::InitKeyEvent(
}
aKeyEvent.mUniqueId = mUniqueId;
aHandler->InitKeyEvent(nativeEvent, aKeyEvent, aIsProcessedByIME,
mInsertString);
aHandler->InitKeyEvent(nativeEvent, aKeyEvent, mInsertString);
NS_OBJC_END_TRY_ABORT_BLOCK;
}

View File

@ -175,8 +175,6 @@ IMContextWrapper::IMContextWrapper(nsWindow* aOwnerWindow)
, mProcessingKeyEvent(nullptr)
, mCompositionState(eCompositionState_NotComposing)
, mIsIMFocused(false)
, mFallbackToKeyEvent(false)
, mKeyboardEventWasDispatched(false)
, mIsDeletingSurrounding(false)
, mLayoutChanged(false)
, mSetCursorPositionOnKeyEvent(true)
@ -486,7 +484,7 @@ IMContextWrapper::OnBlurWindow(nsWindow* aWindow)
bool
IMContextWrapper::OnKeyEvent(nsWindow* aCaller,
GdkEventKey* aEvent,
bool aKeyboardEventWasDispatched /* = false */)
bool aKeyDownEventWasSent /* = false */)
{
NS_PRECONDITION(aEvent, "aEvent must be non-null");
@ -496,10 +494,10 @@ IMContextWrapper::OnKeyEvent(nsWindow* aCaller,
}
MOZ_LOG(gGtkIMLog, LogLevel::Info,
("0x%p OnKeyEvent(aCaller=0x%p, aKeyboardEventWasDispatched=%s), "
("0x%p OnKeyEvent(aCaller=0x%p, aKeyDownEventWasSent=%s), "
"mCompositionState=%s, current context=0x%p, active context=0x%p, "
"aEvent(0x%p): { type=%s, keyval=%s, unicode=0x%X }",
this, aCaller, ToChar(aKeyboardEventWasDispatched),
this, aCaller, ToChar(aKeyDownEventWasSent),
GetCompositionStateName(), GetCurrentContext(), GetActiveContext(),
aEvent, GetEventType(aEvent), gdk_keyval_name(aEvent->keyval),
gdk_keyval_to_unicode(aEvent->keyval)));
@ -527,51 +525,49 @@ IMContextWrapper::OnKeyEvent(nsWindow* aCaller,
mSetCursorPositionOnKeyEvent = false;
}
mKeyboardEventWasDispatched = aKeyboardEventWasDispatched;
mFallbackToKeyEvent = false;
mKeyDownEventWasSent = aKeyDownEventWasSent;
mFilterKeyEvent = true;
mProcessingKeyEvent = aEvent;
gboolean isFiltered =
gtk_im_context_filter_keypress(currentContext, aEvent);
// The caller of this shouldn't handle aEvent anymore if we've dispatched
// composition events or modified content with other events.
bool filterThisEvent = isFiltered && !mFallbackToKeyEvent;
if (IsComposingOnCurrentContext() && !isFiltered &&
aEvent->type == GDK_KEY_PRESS &&
mDispatchedCompositionString.IsEmpty()) {
// A Hangul input engine for SCIM doesn't emit preedit_end
// signal even when composition string becomes empty. On the
// other hand, we should allow to make composition with empty
// string for other languages because there *might* be such
// IM. For compromising this issue, we should dispatch
// compositionend event, however, we don't need to reset IM
// actually.
// NOTE: Don't dispatch key events as "processed by IME" since
// we need to dispatch keyboard events as IME wasn't handled it.
mProcessingKeyEvent = nullptr;
DispatchCompositionCommitEvent(currentContext, &EmptyString());
mProcessingKeyEvent = aEvent;
// In this case, even though we handle the keyboard event here,
// but we should dispatch keydown event as
filterThisEvent = false;
}
// If IME handled the key event but we've not dispatched eKeyDown nor
// eKeyUp event yet, we need to dispatch here because the caller won't
// do it.
if (filterThisEvent) {
MaybeDispatchKeyEventAsProcessedByIME();
// Be aware, the widget might have been gone here.
}
mProcessingKeyEvent = nullptr;
// We filter the key event if the event was not committed (because
// it's probably part of a composition) or if the key event was
// committed _and_ changed. This way we still let key press
// events go through as simple key press events instead of
// composed characters.
bool filterThisEvent = isFiltered && mFilterKeyEvent;
if (IsComposingOnCurrentContext() && !isFiltered) {
if (aEvent->type == GDK_KEY_PRESS) {
if (!mDispatchedCompositionString.IsEmpty()) {
// If there is composition string, we shouldn't dispatch
// any keydown events during composition.
filterThisEvent = true;
} else {
// A Hangul input engine for SCIM doesn't emit preedit_end
// signal even when composition string becomes empty. On the
// other hand, we should allow to make composition with empty
// string for other languages because there *might* be such
// IM. For compromising this issue, we should dispatch
// compositionend event, however, we don't need to reset IM
// actually.
DispatchCompositionCommitEvent(currentContext, &EmptyString());
filterThisEvent = false;
}
} else {
// Key release event may not be consumed by IM, however, we
// shouldn't dispatch any keyup event during composition.
filterThisEvent = true;
}
}
MOZ_LOG(gGtkIMLog, LogLevel::Debug,
("0x%p OnKeyEvent(), succeeded, filterThisEvent=%s "
"(isFiltered=%s, mFallbackToKeyEvent=%s), mCompositionState=%s",
"(isFiltered=%s, mFilterKeyEvent=%s), mCompositionState=%s",
this, ToChar(filterThisEvent), ToChar(isFiltered),
ToChar(mFallbackToKeyEvent), GetCompositionStateName()));
ToChar(mFilterKeyEvent), GetCompositionStateName()));
return filterThisEvent;
}
@ -1306,14 +1302,11 @@ IMContextWrapper::OnCommitCompositionNative(GtkIMContext* aContext,
}
// If IME doesn't change their keyevent that generated this commit,
// we should treat that IME didn't handle the key event because
// web applications want to receive "keydown" and "keypress" event
// in such case.
// don't send it through XIM - just send it as a normal key press
// event.
// NOTE: While a key event is being handled, this might be caused on
// current context. Otherwise, this may be caused on active context.
if (!IsComposingOn(aContext) &&
mProcessingKeyEvent &&
mProcessingKeyEvent->type == GDK_KEY_PRESS &&
if (!IsComposingOn(aContext) && mProcessingKeyEvent &&
aContext == GetCurrentContext()) {
char keyval_utf8[8]; /* should have at least 6 bytes of space */
gint keyval_utf8_len;
@ -1328,9 +1321,7 @@ IMContextWrapper::OnCommitCompositionNative(GtkIMContext* aContext,
("0x%p OnCommitCompositionNative(), "
"we'll send normal key event",
this));
// In this case, eKeyDown and eKeyPress event should be dispatched
// by the caller of OnKeyEvent().
mFallbackToKeyEvent = true;
mFilterKeyEvent = false;
return;
}
}
@ -1364,65 +1355,6 @@ IMContextWrapper::GetCompositionString(GtkIMContext* aContext,
g_free(preedit_string);
}
bool
IMContextWrapper::MaybeDispatchKeyEventAsProcessedByIME()
{
if (!mProcessingKeyEvent || mKeyboardEventWasDispatched ||
!mLastFocusedWindow) {
return true;
}
// A "keydown" or "keyup" event handler may change focus with the
// following event. In such case, we need to cancel this composition.
// So, we need to store IM context now because mComposingContext may be
// overwritten with different context if calling this method recursively.
// Note that we don't need to grab the context here because |context|
// will be used only for checking if it's same as mComposingContext.
GtkIMContext* oldCurrentContext = GetCurrentContext();
GtkIMContext* oldComposingContext = mComposingContext;
RefPtr<nsWindow> lastFocusedWindow(mLastFocusedWindow);
mKeyboardEventWasDispatched = true;
// FYI: We should ignore if default of preceding keydown or keyup event is
// prevented since even on the other browsers, web applications
// cannot cancel the following composition event.
// Spec bug: https://github.com/w3c/uievents/issues/180
bool isCancelled;
lastFocusedWindow->DispatchKeyDownOrKeyUpEvent(mProcessingKeyEvent, true,
&isCancelled);
MOZ_LOG(gGtkIMLog, LogLevel::Debug,
("0x%p MaybeDispatchKeyEventAsProcessedByIME(), keydown or keyup "
"event is dispatched",
this));
if (lastFocusedWindow->IsDestroyed() ||
lastFocusedWindow != mLastFocusedWindow) {
MOZ_LOG(gGtkIMLog, LogLevel::Warning,
("0x%p MaybeDispatchKeyEventAsProcessedByIME(), Warning, the "
"focused widget was destroyed/changed by a key event",
this));
return false;
}
// If the dispatched keydown event caused moving focus and that also
// caused changing active context, we need to cancel composition here.
if (GetCurrentContext() != oldCurrentContext) {
MOZ_LOG(gGtkIMLog, LogLevel::Warning,
("0x%p MaybeDispatchKeyEventAsProcessedByIME(), Warning, the key "
"event causes changing active IM context",
this));
if (mComposingContext == oldComposingContext) {
// Only when the context is still composing, we should call
// ResetIME() here. Otherwise, it should've already been
// cleaned up.
ResetIME();
}
return false;
}
return true;
}
bool
IMContextWrapper::DispatchCompositionStart(GtkIMContext* aContext)
{
@ -1467,16 +1399,50 @@ IMContextWrapper::DispatchCompositionStart(GtkIMContext* aContext)
mCompositionStart = mSelection.mOffset;
mDispatchedCompositionString.Truncate();
// If this composition is started by a key press, we need to dispatch
// eKeyDown or eKeyUp event before dispatching eCompositionStart event.
// Note that dispatching a keyboard event which is marked as "processed
// by IME" is okay since Chromium also dispatches keyboard event as so.
if (!MaybeDispatchKeyEventAsProcessedByIME()) {
MOZ_LOG(gGtkIMLog, LogLevel::Warning,
("0x%p DispatchCompositionStart(), Warning, "
"MaybeDispatchKeyEventAsProcessedByIME() returned false",
if (mProcessingKeyEvent && !mKeyDownEventWasSent &&
mProcessingKeyEvent->type == GDK_KEY_PRESS) {
// A keydown event handler may change focus with the following keydown
// event. In such case, we need to cancel this composition. So, we
// need to store IM context now because mComposingContext may be
// overwritten with different context if calling this method
// recursively.
// Note that we don't need to grab the context here because |context|
// will be used only for checking if it's same as mComposingContext.
GtkIMContext* context = mComposingContext;
// If this composition is started by a native keydown event, we need to
// dispatch our keydown event here (before composition start).
bool isCancelled;
mLastFocusedWindow->DispatchKeyDownEvent(mProcessingKeyEvent,
&isCancelled);
MOZ_LOG(gGtkIMLog, LogLevel::Debug,
("0x%p DispatchCompositionStart(), preceding keydown event is "
"dispatched",
this));
return false;
if (lastFocusedWindow->IsDestroyed() ||
lastFocusedWindow != mLastFocusedWindow) {
MOZ_LOG(gGtkIMLog, LogLevel::Warning,
("0x%p DispatchCompositionStart(), Warning, the focused "
"widget was destroyed/changed by keydown event",
this));
return false;
}
// If the dispatched keydown event caused moving focus and that also
// caused changing active context, we need to cancel composition here.
if (GetCurrentContext() != context) {
MOZ_LOG(gGtkIMLog, LogLevel::Warning,
("0x%p DispatchCompositionStart(), Warning, the preceding "
"keydown event causes changing active IM context",
this));
if (mComposingContext == context) {
// Only when the context is still composing, we should call
// ResetIME() here. Otherwise, it should've already been
// cleaned up.
ResetIME();
}
return false;
}
}
RefPtr<TextEventDispatcher> dispatcher = GetTextEventDispatcher();
@ -1534,15 +1500,6 @@ IMContextWrapper::DispatchCompositionChangeEvent(
return false;
}
}
// If this composition string change caused by a key press, we need to
// dispatch eKeyDown or eKeyUp before dispatching eCompositionChange event.
else if (!MaybeDispatchKeyEventAsProcessedByIME()) {
MOZ_LOG(gGtkIMLog, LogLevel::Warning,
("0x%p DispatchCompositionChangeEvent(), Warning, "
"MaybeDispatchKeyEventAsProcessedByIME() returned false",
this));
return false;
}
RefPtr<TextEventDispatcher> dispatcher = GetTextEventDispatcher();
nsresult rv = dispatcher->BeginNativeInputTransaction();
@ -1632,14 +1589,6 @@ IMContextWrapper::DispatchCompositionCommitEvent(
return false;
}
// TODO: We need special care to handle request to commit composition
// by content while we're committing composition because we have
// commit string information now but IME may not have composition
// anymore. Therefore, we may not be able to handle commit as
// expected. However, this is rare case because this situation
// never occurs with remote content. So, it's okay to fix this
// issue later. (Perhaps, TextEventDisptcher should do it for
// all platforms. E.g., creating WillCommitComposition()?)
if (!IsComposing()) {
if (!aCommitString || aCommitString->IsEmpty()) {
MOZ_LOG(gGtkIMLog, LogLevel::Error,
@ -1656,16 +1605,6 @@ IMContextWrapper::DispatchCompositionCommitEvent(
return false;
}
}
// If this commit caused by a key press, we need to dispatch eKeyDown or
// eKeyUp before dispatching composition events.
else if (!MaybeDispatchKeyEventAsProcessedByIME()) {
MOZ_LOG(gGtkIMLog, LogLevel::Warning,
("0x%p DispatchCompositionCommitEvent(), Warning, "
"MaybeDispatchKeyEventAsProcessedByIME() returned false",
this));
mCompositionState = eCompositionState_NotComposing;
return false;
}
RefPtr<TextEventDispatcher> dispatcher = GetTextEventDispatcher();
nsresult rv = dispatcher->BeginNativeInputTransaction();
@ -2360,16 +2299,6 @@ IMContextWrapper::DeleteText(GtkIMContext* aContext,
return NS_ERROR_FAILURE;
}
// If this deleting text caused by a key press, we need to dispatch
// eKeyDown or eKeyUp before dispatching eContentCommandDelete event.
if (!MaybeDispatchKeyEventAsProcessedByIME()) {
MOZ_LOG(gGtkIMLog, LogLevel::Warning,
("0x%p DeleteText(), Warning, "
"MaybeDispatchKeyEventAsProcessedByIME() returned false",
this));
return NS_ERROR_FAILURE;
}
// Delete the selection
WidgetContentCommandEvent contentCommandEvent(true, eContentCommandDelete,
mLastFocusedWindow);

View File

@ -65,26 +65,13 @@ public:
void OnSelectionChange(nsWindow* aCaller,
const IMENotification& aIMENotification);
/**
* OnKeyEvent() is called when aWindow gets a native key press event or a
* native key release event. If this returns true, the key event was
* filtered by IME. Otherwise, this returns false.
* NOTE: When the native key press event starts composition, this returns
* true but dispatches an eKeyDown event or eKeyUp event before
* dispatching composition events or content command event.
*
* @param aWindow A window on which user operate the
* key.
* @param aEvent A native key press or release
* event.
* @param aKeyboardEventWasDispatched true if eKeyDown or eKeyUp event
* for aEvent has already been
* dispatched. In this case,
* this class doesn't dispatch
* keyboard event anymore.
*/
// OnKeyEvent is called when aWindow gets a native key press event or a
// native key release event. If this returns TRUE, the key event was
// filtered by IME. Otherwise, this returns FALSE.
// NOTE: When the keypress event starts composition, this returns TRUE but
// this dispatches keydown event before compositionstart event.
bool OnKeyEvent(nsWindow* aWindow, GdkEventKey* aEvent,
bool aKeyboardEventWasDispatched = false);
bool aKeyDownEventWasSent = false);
// IME related nsIWidget methods.
nsresult EndIMEComposition(nsWindow* aCaller);
@ -276,20 +263,16 @@ protected:
// mIsIMFocused is set to TRUE when we call gtk_im_context_focus_in(). And
// it's set to FALSE when we call gtk_im_context_focus_out().
bool mIsIMFocused;
// mFallbackToKeyEvent is set to false when this class starts to handle
// a native key event (at that time, mProcessingKeyEvent is set to the
// native event). If active IME just commits composition with a character
// which is produced by the key with current keyboard layout, this is set
// to true.
bool mFallbackToKeyEvent;
// mKeyboardEventWasDispatched is used by OnKeyEvent() and
// MaybeDispatchKeyEventAsProcessedByIME().
// MaybeDispatchKeyEventAsProcessedByIME() dispatches an eKeyDown or
// eKeyUp event event if the composition is caused by a native
// key press event. If this is true, a keyboard event has been dispatched
// for the native event. If so, MaybeDispatchKeyEventAsProcessedByIME()
// won't dispatch keyboard event anymore.
bool mKeyboardEventWasDispatched;
// mFilterKeyEvent is used by OnKeyEvent(). If the commit event should
// be processed as simple key event, this is set to TRUE by the commit
// handler.
bool mFilterKeyEvent;
// mKeyDownEventWasSent is used by OnKeyEvent() and
// DispatchCompositionStart(). DispatchCompositionStart() dispatches
// a keydown event if the composition start is caused by a native
// keypress event. If this is true, the keydown event has been dispatched.
// Then, DispatchCompositionStart() doesn't dispatch keydown event.
bool mKeyDownEventWasSent;
// mIsDeletingSurrounding is true while OnDeleteSurroundingNative() is
// trying to delete the surrounding text.
bool mIsDeletingSurrounding;
@ -460,27 +443,11 @@ protected:
* Following methods dispatch gecko events. Then, the focused widget
* can be destroyed, and also it can be stolen focus. If they returns
* FALSE, callers cannot continue the composition.
* - MaybeDispatchKeyEventAsProcessedByIME
* - DispatchCompositionStart
* - DispatchCompositionChangeEvent
* - DispatchCompositionCommitEvent
*/
/**
* Dispatch an eKeyDown or eKeyUp event whose mKeyCode value is
* NS_VK_PROCESSKEY and mKeyNameIndex is KEY_NAME_INDEX_Process if
* mProcessingKeyEvent is not nullptr and mKeyboardEventWasDispatched is
* still false. If this dispatches a keyboard event, this sets
* mKeyboardEventWasDispatched to true.
*
* @return If the caller can continue to handle
* composition, returns true. Otherwise,
* false. For example, if focus is moved
* by dispatched keyboard event, returns
* false.
*/
bool MaybeDispatchKeyEventAsProcessedByIME();
/**
* Dispatches a composition start event.
*

View File

@ -931,19 +931,14 @@ KeymapWrapper::ComputeDOMCodeNameIndex(const GdkEventKey* aGdkKeyEvent)
/* static */ void
KeymapWrapper::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
GdkEventKey* aGdkKeyEvent,
bool aIsProcessedByIME)
GdkEventKey* aGdkKeyEvent)
{
MOZ_ASSERT(!aIsProcessedByIME || aKeyEvent.mMessage != eKeyPress,
"If the key event is handled by IME, keypress event shouldn't be fired");
KeymapWrapper* keymapWrapper = GetInstance();
aKeyEvent.mCodeNameIndex = ComputeDOMCodeNameIndex(aGdkKeyEvent);
MOZ_ASSERT(aKeyEvent.mCodeNameIndex != CODE_NAME_INDEX_USE_STRING);
aKeyEvent.mKeyNameIndex =
aIsProcessedByIME ? KEY_NAME_INDEX_Process :
keymapWrapper->ComputeDOMKeyNameIndex(aGdkKeyEvent);
keymapWrapper->ComputeDOMKeyNameIndex(aGdkKeyEvent);
if (aKeyEvent.mKeyNameIndex == KEY_NAME_INDEX_Unidentified) {
uint32_t charCode = GetCharCodeFor(aGdkKeyEvent);
if (!charCode) {
@ -956,11 +951,10 @@ KeymapWrapper::InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
AppendUCS4ToUTF16(charCode, aKeyEvent.mKeyValue);
}
}
aKeyEvent.mKeyCode = ComputeDOMKeyCode(aGdkKeyEvent);
if (aIsProcessedByIME) {
aKeyEvent.mKeyCode = NS_VK_PROCESSKEY;
} else if (aKeyEvent.mKeyNameIndex != KEY_NAME_INDEX_USE_STRING ||
aKeyEvent.mMessage != eKeyPress) {
if (aKeyEvent.mKeyNameIndex != KEY_NAME_INDEX_USE_STRING ||
aKeyEvent.mMessage != eKeyPress) {
aKeyEvent.mKeyCode = ComputeDOMKeyCode(aGdkKeyEvent);
} else {
aKeyEvent.mKeyCode = 0;

View File

@ -131,11 +131,9 @@ public:
* @param aKeyEvent It's an WidgetKeyboardEvent which needs to be
* initialized.
* @param aGdkKeyEvent A native GDK key event.
* @param aIsProcessedByIME true if aGdkKeyEvent is handled by IME.
*/
static void InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
GdkEventKey* aGdkKeyEvent,
bool aIsProcessedByIME);
GdkEventKey* aGdkKeyEvent);
/**
* WillDispatchKeyboardEvent() is called via

View File

@ -2937,15 +2937,13 @@ IsCtrlAltTab(GdkEventKey *aEvent)
}
bool
nsWindow::DispatchKeyDownOrKeyUpEvent(GdkEventKey* aEvent,
bool aIsProcessedByIME,
bool* aIsCancelled)
nsWindow::DispatchKeyDownEvent(GdkEventKey *aEvent, bool *aCancelled)
{
MOZ_ASSERT(aIsCancelled, "aCancelled must not be null");
NS_PRECONDITION(aCancelled, "aCancelled must not be null");
*aIsCancelled = false;
*aCancelled = false;
if (aEvent->type == GDK_KEY_PRESS && IsCtrlAltTab(aEvent)) {
if (IsCtrlAltTab(aEvent)) {
return false;
}
@ -2955,14 +2953,13 @@ nsWindow::DispatchKeyDownOrKeyUpEvent(GdkEventKey* aEvent,
return FALSE;
}
EventMessage message =
aEvent->type == GDK_KEY_PRESS ? eKeyDown : eKeyUp;
WidgetKeyboardEvent keyEvent(true, message, this);
KeymapWrapper::InitKeyEvent(keyEvent, aEvent, aIsProcessedByIME);
WidgetKeyboardEvent keydownEvent(true, eKeyDown, this);
KeymapWrapper::InitKeyEvent(keydownEvent, aEvent);
nsEventStatus status = nsEventStatus_eIgnore;
bool dispatched =
dispatcher->DispatchKeyboardEvent(message, keyEvent, status, aEvent);
*aIsCancelled = (status == nsEventStatus_eConsumeNoDefault);
dispatcher->DispatchKeyboardEvent(eKeyDown, keydownEvent,
status, aEvent);
*aCancelled = (status == nsEventStatus_eConsumeNoDefault);
return dispatched ? TRUE : FALSE;
}
@ -3048,7 +3045,7 @@ nsWindow::OnKeyPressEvent(GdkEventKey *aEvent)
// KEYDOWN -> KEYPRESS -> KEYUP -> KEYDOWN -> KEYPRESS -> KEYUP...
bool isKeyDownCancelled = false;
if (DispatchKeyDownOrKeyUpEvent(aEvent, false, &isKeyDownCancelled) &&
if (DispatchKeyDownEvent(aEvent, &isKeyDownCancelled) &&
(MOZ_UNLIKELY(mIsDestroyed) || isKeyDownCancelled)) {
return TRUE;
}
@ -3097,7 +3094,7 @@ nsWindow::OnKeyPressEvent(GdkEventKey *aEvent)
}
WidgetKeyboardEvent keypressEvent(true, eKeyPress, this);
KeymapWrapper::InitKeyEvent(keypressEvent, aEvent, false);
KeymapWrapper::InitKeyEvent(keypressEvent, aEvent);
// before we dispatch a key, check if it's the context menu key.
// If so, send a context menu key event instead.
@ -3181,7 +3178,7 @@ nsWindow::MaybeDispatchContextMenuEvent(const GdkEventKey* aEvent)
}
gboolean
nsWindow::OnKeyReleaseEvent(GdkEventKey* aEvent)
nsWindow::OnKeyReleaseEvent(GdkEventKey *aEvent)
{
LOGFOCUS(("OnKeyReleaseEvent [%p]\n", (void *)this));
@ -3189,11 +3186,17 @@ nsWindow::OnKeyReleaseEvent(GdkEventKey* aEvent)
return TRUE;
}
bool isCancelled = false;
if (NS_WARN_IF(!DispatchKeyDownOrKeyUpEvent(aEvent, false, &isCancelled))) {
return FALSE;
RefPtr<TextEventDispatcher> dispatcher = GetTextEventDispatcher();
nsresult rv = dispatcher->BeginNativeInputTransaction();
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
WidgetKeyboardEvent keyupEvent(true, eKeyUp, this);
KeymapWrapper::InitKeyEvent(keyupEvent, aEvent);
nsEventStatus status = nsEventStatus_eIgnore;
dispatcher->DispatchKeyboardEvent(eKeyUp, keyupEvent, status, aEvent);
return TRUE;
}

View File

@ -278,20 +278,10 @@ public:
guint aTime);
static void UpdateDragStatus (GdkDragContext *aDragContext,
nsIDragService *aDragService);
/**
* DispatchKeyDownOrKeyUpEvent() dispatches eKeyDown or eKeyUp event.
*
* @param aEvent A native GDK_KEY_PRESS or GDK_KEY_RELEASE
* event.
* @param aProcessedByIME true if the event is handled by IME.
* @param aIsCancelled [Out] true if the default is prevented.
* @return true if eKeyDown event is actually dispatched.
* Otherwise, false.
*/
bool DispatchKeyDownOrKeyUpEvent(GdkEventKey* aEvent,
bool aProcessedByIME,
bool* aIsCancelled);
// If this dispatched the keydown event actually, this returns TRUE,
// otherwise, FALSE.
bool DispatchKeyDownEvent(GdkEventKey *aEvent,
bool *aIsCancelled);
WidgetEventTime GetWidgetEventTime(guint32 aEventTime);
mozilla::TimeStamp GetEventTimeStamp(guint32 aEventTime);
mozilla::CurrentX11TimeGetter* GetCurrentTimeGetter();

View File

@ -3023,10 +3023,10 @@ function* runKeyEventTests()
const WIN_VK_PROCESSKEY_WITH_SC_A = WIN_VK_PROCESSKEY | 0x001E0000;
yield testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_PROCESSKEY_WITH_SC_A,
modifiers:{}, chars:"a"},
["a", "a", "Process"], "KeyA", KeyboardEvent.DOM_VK_PROCESSKEY, "a", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
["a", "a", "Unidentified" /* TODO: Process */], "KeyA", 0 /* TODO: 0xE5 */, "a", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
yield testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_PROCESSKEY_WITH_SC_A,
modifiers:{altKey:1}, chars:"a"},
["a", "a", "Process"], "KeyA", KeyboardEvent.DOM_VK_PROCESSKEY, "a", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
["a", "a", "Unidentified" /* TODO: Process */], "KeyA", 0 /* TODO: 0xE5 */, "a", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
// US
// Alphabet

View File

@ -4805,7 +4805,7 @@ KeyboardLayout::ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const
// VK_PROCESSKEY means IME already consumed the key event.
case VK_PROCESSKEY:
return NS_VK_PROCESSKEY;
return 0;
// VK_PACKET is generated by SendInput() API, we don't need to
// care this message as key event.
case VK_PACKET: