/* -*- 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/BasicEvents.h" #include "mozilla/EventForwards.h" #include "mozilla/Maybe.h" #include "mozilla/TextEventDispatcher.h" #include "mozilla/TextEventDispatcherListener.h" #include "nsITextInputProcessor.h" #include "nsITextInputProcessorCallback.h" #include "nsTArray.h" class nsPIDOMWindowInner; 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 MOZ_CAN_RUN_SCRIPT_BOUNDARY 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; /** * TextInputProcessor manages modifier key state. E.g., when it dispatches * a modifier keydown event, activates proper modifier state and when it * dispatches a modifier keyup event, inactivates proper modifier state. * This returns all active modifiers in the instance. */ Modifiers GetActiveModifiers() const { return mModifierKeyDataArray ? mModifierKeyDataArray->GetActiveModifiers() : MODIFIER_NONE; } /** * This begins transaction for fuzzing. This must be called only by * FuzzingFunctions since this skips the permission check. * See explanation of nsITextInputProcessor::BeginInputTransaction() for * the detail. */ nsresult BeginInputTransactionForFuzzing( nsPIDOMWindowInner* aWindow, nsITextInputProcessorCallback* aCallback, bool* aSucceeded); /** * The following Keydown() and KeyUp() are same as nsITextInputProcessor's * same name methods except the type of event class. See explanation in * nsITextInputProcessor for the detail. */ MOZ_CAN_RUN_SCRIPT nsresult Keydown(const WidgetKeyboardEvent& aKeyboardEvent, uint32_t aKeyFlags, uint32_t* aConsumedFlags = nullptr); nsresult Keyup(const WidgetKeyboardEvent& aKeyboardEvent, uint32_t aKeyFlags, bool* aDoDefault = nullptr); /** * GuessCodeNameIndexOfPrintableKeyInUSEnglishLayout() returns CodeNameIndex * of a printable key which is in usual keyboard of the platform and when * active keyboard layout is US-English. * Note that this does not aware of option key mapping on macOS. * * @param aKeyValue The key value. Must be a character which can * be inputted with US-English keyboard layout. * @param aLocation The location of the key. This is important * to distinguish whether the key is in Standard * or Numpad. If this is not some, treated as * Standard. * @return Returns CODE_NAME_INDEX_UNKNOWN if there is * no proper key. */ static CodeNameIndex GuessCodeNameIndexOfPrintableKeyInUSEnglishLayout( const nsAString& aKeyValue, const Maybe& aLocation); /** * GuessKeyCodeOfPrintableKeyInUSEnglishLayout() returns a key code value * of a printable key which is in usual keyboard of the platform and when * active keyboard layout is US-English. * Note that this does not aware of option key mapping on macOS. * * @param aKeyValue The key value. Must be a character which can * be inputted with US-English keyboard layout. * @param aLocation The location of the key. This is important * to distinguish whether the key is in Standard * or Numpad. If this is not some, treated as * Standard. * @return Returns 0 if there is no proper key to input * aKeyValue with US-English keyboard layout. */ static uint32_t GuessKeyCodeOfPrintableKeyInUSEnglishLayout( const nsAString& aKeyValue, const Maybe& aLocation); protected: virtual ~TextInputProcessor(); private: bool IsComposing() const; nsresult BeginInputTransactionInternal( mozIDOMWindow* aWindow, nsITextInputProcessorCallback* aCallback, bool aForTests, bool& aSucceeded); MOZ_CAN_RUN_SCRIPT nsresult CommitCompositionInternal( const WidgetKeyboardEvent* aKeyboardEvent = nullptr, uint32_t aKeyFlags = 0, const nsAString* aCommitString = nullptr, bool* aSucceeded = nullptr); MOZ_CAN_RUN_SCRIPT nsresult CancelCompositionInternal(const WidgetKeyboardEvent* aKeyboardEvent = nullptr, uint32_t aKeyFlags = 0); MOZ_CAN_RUN_SCRIPT 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); /** * InitEditCommands() initializes edit commands of aKeyboardEvent. * This must be called only in a content process, and aKeyboardEvent must * be used only for `eKeyPress` event. */ MOZ_CAN_RUN_SCRIPT nsresult InitEditCommands(WidgetKeyboardEvent& aKeyboardEvent) const; 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) {} }; MOZ_CAN_RUN_SCRIPT 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() = default; }; 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_