nsresult TextEventDispatcher::StartCompositionAutomaticallyIfNecessary( nsEventStatus& aStatus) { if (IsComposing()) { return NS_OK; } nsresult rv = StartComposition(aStatus); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } // If started composition has already been committed, we shouldn't dispatch // the compositionchange event. if (!IsComposing()) { aStatus = nsEventStatus_eConsumeNoDefault; return NS_OK; } // Note that the widget might be destroyed during a call of // StartComposition(). In such case, we shouldn't keep dispatching next // event. rv = GetState(); if (NS_FAILED(rv)) { MOZ_ASSERT(rv != NS_ERROR_NOT_INITIALIZED, "aDispatcher must still be initialized in this case"); aStatus = nsEventStatus_eConsumeNoDefault; return NS_OK; // Don't throw exception in this case } aStatus = nsEventStatus_eIgnore; return NS_OK; }
void KeyboardEvent::GetInitDict(KeyboardEventInit& aParam) { GetKey(aParam.mKey); GetCode(aParam.mCode); aParam.mLocation = Location(); aParam.mRepeat = Repeat(); aParam.mIsComposing = IsComposing(); // legacy attributes aParam.mKeyCode = KeyCode(); aParam.mCharCode = CharCode(); aParam.mWhich = Which(); // modifiers from EventModifierInit aParam.mCtrlKey = CtrlKey(); aParam.mShiftKey = ShiftKey(); aParam.mAltKey = AltKey(); aParam.mMetaKey = MetaKey(); WidgetKeyboardEvent* internalEvent = mEvent->AsKeyboardEvent(); aParam.mModifierAltGraph = internalEvent->IsAltGraph(); aParam.mModifierCapsLock = internalEvent->IsCapsLocked(); aParam.mModifierFn = internalEvent->IsFn(); aParam.mModifierFnLock = internalEvent->IsFnLocked(); aParam.mModifierNumLock = internalEvent->IsNumLocked(); aParam.mModifierOS = internalEvent->IsOS(); aParam.mModifierScrollLock = internalEvent->IsScrollLocked(); aParam.mModifierSymbol = internalEvent->IsSymbol(); aParam.mModifierSymbolLock = internalEvent->IsSymbolLocked(); // EventInit aParam.mBubbles = internalEvent->mFlags.mBubbles; aParam.mCancelable = internalEvent->mFlags.mCancelable; }
nsresult TextEventDispatcher::BeginInputTransactionInternal( TextEventDispatcherListener* aListener, bool aForTests) { if (NS_WARN_IF(!aListener)) { return NS_ERROR_INVALID_ARG; } nsCOMPtr<TextEventDispatcherListener> listener = do_QueryReferent(mListener); if (listener) { if (listener == aListener && mForTests == aForTests) { return NS_OK; } // If this has composition or is dispatching an event, any other listener // can steal ownership. Especially, if the latter case is allowed, // nobody cannot begin input transaction with this if a modal dialog is // opened during dispatching an event. if (IsComposing() || IsDispatchingEvent()) { return NS_ERROR_ALREADY_INITIALIZED; } } mListener = do_GetWeakReference(aListener); mForTests = aForTests; if (listener && listener != aListener) { listener->OnRemovedFrom(this); } return NS_OK; }
nsresult TextEventDispatcher::CommitComposition(nsEventStatus& aStatus, const nsAString* aCommitString) { aStatus = nsEventStatus_eIgnore; nsresult rv = GetState(); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } // When there is no composition, caller shouldn't try to commit composition // with non-existing composition string nor commit composition with empty // string. if (NS_WARN_IF(!IsComposing() && (!aCommitString || aCommitString->IsEmpty()))) { return NS_ERROR_FAILURE; } nsCOMPtr<nsIWidget> widget(mWidget); rv = StartCompositionAutomaticallyIfNecessary(aStatus); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } if (aStatus == nsEventStatus_eConsumeNoDefault) { return NS_OK; } // End current composition and make this free for other IMEs. mIsComposing = false; uint32_t message = aCommitString ? NS_COMPOSITION_COMMIT : NS_COMPOSITION_COMMIT_AS_IS; WidgetCompositionEvent compositionCommitEvent(true, message, widget); InitEvent(compositionCommitEvent); if (message == NS_COMPOSITION_COMMIT) { compositionCommitEvent.mData = *aCommitString; } rv = DispatchEvent(widget, compositionCommitEvent, aStatus); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } return NS_OK; }
void TextEventDispatcher::EndInputTransaction(TextEventDispatcherListener* aListener) { if (NS_WARN_IF(IsComposing()) || NS_WARN_IF(IsDispatchingEvent())) { return; } nsCOMPtr<TextEventDispatcherListener> listener = do_QueryReferent(mListener); if (NS_WARN_IF(!listener)) { return; } if (NS_WARN_IF(listener != aListener)) { return; } mListener = nullptr; listener->OnRemovedFrom(this); }
bool TextEventDispatcher::DispatchKeyboardEventInternal( uint32_t aMessage, const WidgetKeyboardEvent& aKeyboardEvent, nsEventStatus& aStatus, uint32_t aIndexOfKeypress) { MOZ_ASSERT(aMessage == NS_KEY_DOWN || aMessage == NS_KEY_UP || aMessage == NS_KEY_PRESS, "Invalid aMessage value"); nsresult rv = GetState(); if (NS_WARN_IF(NS_FAILED(rv))) { return false; } // If the key shouldn't cause keypress events, don't this patch them. if (aMessage == NS_KEY_PRESS && !aKeyboardEvent.ShouldCauseKeypressEvents()) { return false; } // Basically, key events shouldn't be dispatched during composition. if (IsComposing()) { // However, if we need to behave like other browsers, we need the keydown // and keyup events. Note that this behavior is also allowed by D3E spec. // FYI: keypress events must not be fired during composition. if (!sDispatchKeyEventsDuringComposition || aMessage == NS_KEY_PRESS) { return false; } // XXX If there was mOnlyContentDispatch for this case, it might be useful // because our chrome doesn't assume that key events are fired during // composition. } WidgetKeyboardEvent keyEvent(true, aMessage, mWidget); InitEvent(keyEvent); keyEvent.AssignKeyEventData(aKeyboardEvent, false); if (aStatus == nsEventStatus_eConsumeNoDefault) { // If the key event should be dispatched as consumed event, marking it here. // This is useful to prevent double action. E.g., when the key was already // handled by system, our chrome shouldn't handle it. keyEvent.mFlags.mDefaultPrevented = true; } // Corrects each member for the specific key event type. if (aMessage == NS_KEY_DOWN || aMessage == NS_KEY_UP) { MOZ_ASSERT(!aIndexOfKeypress, "aIndexOfKeypress must be 0 for either NS_KEY_DOWN or NS_KEY_UP"); // charCode of keydown and keyup should be 0. keyEvent.charCode = 0; } else if (keyEvent.mKeyNameIndex != KEY_NAME_INDEX_USE_STRING) { MOZ_ASSERT(!aIndexOfKeypress, "aIndexOfKeypress must be 0 for NS_KEY_PRESS of non-printable key"); // If keypress event isn't caused by printable key, its charCode should // be 0. keyEvent.charCode = 0; } else { MOZ_RELEASE_ASSERT( !aIndexOfKeypress || aIndexOfKeypress < keyEvent.mKeyValue.Length(), "aIndexOfKeypress must be 0 - mKeyValue.Length() - 1"); keyEvent.keyCode = 0; wchar_t ch = keyEvent.mKeyValue.IsEmpty() ? 0 : keyEvent.mKeyValue[aIndexOfKeypress]; keyEvent.charCode = static_cast<uint32_t>(ch); if (ch) { keyEvent.mKeyValue.Assign(ch); } else { keyEvent.mKeyValue.Truncate(); } } if (aMessage == NS_KEY_UP) { // mIsRepeat of keyup event must be false. keyEvent.mIsRepeat = false; } // mIsComposing should be initialized later. keyEvent.mIsComposing = false; // XXX Currently, we don't support to dispatch key event with native key // event information. keyEvent.mNativeKeyEvent = nullptr; // XXX Currently, we don't support to dispatch key events with data for // plugins. keyEvent.mPluginEvent.Clear(); // TODO: Manage mUniqueId here. DispatchEvent(mWidget, keyEvent, aStatus); return true; }