/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_textinputprocessor_h_ #define mozilla_dom_textinputprocessor_h_ #include "mozilla/Attributes.h" #include "mozilla/EventForwards.h" #include "mozilla/TextEventDispatcher.h" #include "mozilla/TextEventDispatcherListener.h" #include "nsITextInputProcessor.h" #include "nsITextInputProcessorCallback.h" #include "nsTArray.h" namespace mozilla { namespace dom { class KeyboardEvent; } // namespace dom class TextInputProcessor final : public nsITextInputProcessor , public widget::TextEventDispatcherListener { typedef mozilla::widget::IMENotification IMENotification; typedef mozilla::widget::IMENotificationRequests IMENotificationRequests; typedef mozilla::widget::TextEventDispatcher TextEventDispatcher; public: TextInputProcessor(); NS_DECL_ISUPPORTS NS_DECL_NSITEXTINPUTPROCESSOR // TextEventDispatcherListener NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher, const IMENotification& aNotification) override; NS_IMETHOD_(IMENotificationRequests) GetIMENotificationRequests() override; NS_IMETHOD_(void) OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher) override; NS_IMETHOD_(void) WillDispatchKeyboardEvent( TextEventDispatcher* aTextEventDispatcher, WidgetKeyboardEvent& aKeyboardEvent, uint32_t aIndexOfKeypress, void* aData) override; protected: virtual ~TextInputProcessor(); private: bool IsComposing() const; nsresult BeginInputTransactionInternal( mozIDOMWindow* aWindow, nsITextInputProcessorCallback* aCallback, bool aForTests, bool& aSucceeded); nsresult CommitCompositionInternal( const WidgetKeyboardEvent* aKeyboardEvent = nullptr, uint32_t aKeyFlags = 0, const nsAString* aCommitString = nullptr, bool* aSucceeded = nullptr); nsresult CancelCompositionInternal( const WidgetKeyboardEvent* aKeyboardEvent = nullptr, uint32_t aKeyFlags = 0); nsresult KeydownInternal(const WidgetKeyboardEvent& aKeyboardEvent, uint32_t aKeyFlags, bool aAllowToDispatchKeypress, uint32_t& aConsumedFlags); nsresult KeyupInternal(const WidgetKeyboardEvent& aKeyboardEvent, uint32_t aKeyFlags, bool& aDoDefault); nsresult IsValidStateForComposition(); void UnlinkFromTextEventDispatcher(); nsresult PrepareKeyboardEventToDispatch(WidgetKeyboardEvent& aKeyboardEvent, uint32_t aKeyFlags); bool IsValidEventTypeForComposition( const WidgetKeyboardEvent& aKeyboardEvent) const; nsresult PrepareKeyboardEventForComposition( dom::KeyboardEvent* aDOMKeyEvent, uint32_t& aKeyFlags, uint8_t aOptionalArgc, WidgetKeyboardEvent*& aKeyboardEvent); struct EventDispatcherResult { nsresult mResult; bool mDoDefault; bool mCanContinue; EventDispatcherResult() : mResult(NS_OK) , mDoDefault(true) , mCanContinue(true) { } }; EventDispatcherResult MaybeDispatchKeydownForComposition( const WidgetKeyboardEvent* aKeyboardEvent, uint32_t aKeyFlags); EventDispatcherResult MaybeDispatchKeyupForComposition( const WidgetKeyboardEvent* aKeyboardEvent, uint32_t aKeyFlags); /** * AutoPendingCompositionResetter guarantees to clear all pending composition * data in its destructor. */ class MOZ_STACK_CLASS AutoPendingCompositionResetter { public: explicit AutoPendingCompositionResetter(TextInputProcessor* aTIP); ~AutoPendingCompositionResetter(); private: RefPtr mTIP; }; /** * TextInputProcessor manages modifier state both with .key and .code. * For example, left shift key up shouldn't cause inactivating shift state * while right shift key is being pressed. */ struct ModifierKeyData { // One of modifier key name KeyNameIndex mKeyNameIndex; // Any code name is allowed. CodeNameIndex mCodeNameIndex; // A modifier key flag which is activated by the key. Modifiers mModifier; explicit ModifierKeyData(const WidgetKeyboardEvent& aKeyboardEvent); bool operator==(const ModifierKeyData& aOther) const { return mKeyNameIndex == aOther.mKeyNameIndex && mCodeNameIndex == aOther.mCodeNameIndex; } }; class ModifierKeyDataArray : public nsTArray { NS_INLINE_DECL_REFCOUNTING(ModifierKeyDataArray) public: Modifiers GetActiveModifiers() const; void ActivateModifierKey(const ModifierKeyData& aModifierKeyData); void InactivateModifierKey(const ModifierKeyData& aModifierKeyData); void ToggleModifierKey(const ModifierKeyData& aModifierKeyData); private: virtual ~ModifierKeyDataArray() { } }; Modifiers GetActiveModifiers() const { return mModifierKeyDataArray ? mModifierKeyDataArray->GetActiveModifiers() : 0; } void EnsureModifierKeyDataArray() { if (mModifierKeyDataArray) { return; } mModifierKeyDataArray = new ModifierKeyDataArray(); } void ActivateModifierKey(const ModifierKeyData& aModifierKeyData) { EnsureModifierKeyDataArray(); mModifierKeyDataArray->ActivateModifierKey(aModifierKeyData); } void InactivateModifierKey(const ModifierKeyData& aModifierKeyData) { if (!mModifierKeyDataArray) { return; } mModifierKeyDataArray->InactivateModifierKey(aModifierKeyData); } void ToggleModifierKey(const ModifierKeyData& aModifierKeyData) { EnsureModifierKeyDataArray(); mModifierKeyDataArray->ToggleModifierKey(aModifierKeyData); } TextEventDispatcher* mDispatcher; // [Weak] nsCOMPtr mCallback; RefPtr mModifierKeyDataArray; bool mForTests; }; } // namespace mozilla #endif // #ifndef mozilla_dom_textinputprocessor_h_