TextInputProcessor.h (9879B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_textinputprocessor_h_ 8 #define mozilla_dom_textinputprocessor_h_ 9 10 #include "mozilla/Attributes.h" 11 #include "mozilla/BasicEvents.h" 12 #include "mozilla/EventForwards.h" 13 #include "mozilla/Maybe.h" 14 #include "mozilla/TextEventDispatcher.h" 15 #include "mozilla/TextEventDispatcherListener.h" 16 #include "nsITextInputProcessor.h" 17 #include "nsITextInputProcessorCallback.h" 18 #include "nsTArray.h" 19 20 class nsPIDOMWindowInner; 21 22 namespace mozilla { 23 24 namespace dom { 25 class KeyboardEvent; 26 } // namespace dom 27 28 class TextInputProcessor final : public nsITextInputProcessor, 29 public widget::TextEventDispatcherListener { 30 typedef mozilla::widget::IMENotification IMENotification; 31 typedef mozilla::widget::IMENotificationRequests IMENotificationRequests; 32 typedef mozilla::widget::TextEventDispatcher TextEventDispatcher; 33 34 public: 35 TextInputProcessor(); 36 37 NS_DECL_ISUPPORTS 38 NS_DECL_NSITEXTINPUTPROCESSOR 39 40 // TextEventDispatcherListener 41 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD 42 NotifyIME(TextEventDispatcher* aTextEventDispatcher, 43 const IMENotification& aNotification) override; 44 45 NS_IMETHOD_(IMENotificationRequests) GetIMENotificationRequests() override; 46 47 NS_IMETHOD_(void) 48 OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher) override; 49 50 NS_IMETHOD_(void) 51 WillDispatchKeyboardEvent(TextEventDispatcher* aTextEventDispatcher, 52 WidgetKeyboardEvent& aKeyboardEvent, 53 uint32_t aIndexOfKeypress, void* aData) override; 54 55 /** 56 * TextInputProcessor manages modifier key state. E.g., when it dispatches 57 * a modifier keydown event, activates proper modifier state and when it 58 * dispatches a modifier keyup event, inactivates proper modifier state. 59 * This returns all active modifiers in the instance. 60 */ 61 Modifiers GetActiveModifiers() const { 62 return mModifierKeyDataArray ? mModifierKeyDataArray->GetActiveModifiers() 63 : MODIFIER_NONE; 64 } 65 66 /** 67 * This begins transaction for fuzzing. This must be called only by 68 * FuzzingFunctions since this skips the permission check. 69 * See explanation of nsITextInputProcessor::BeginInputTransaction() for 70 * the detail. 71 */ 72 nsresult BeginInputTransactionForFuzzing( 73 nsPIDOMWindowInner* aWindow, nsITextInputProcessorCallback* aCallback, 74 bool* aSucceeded); 75 76 /** 77 * The following Keydown() and KeyUp() are same as nsITextInputProcessor's 78 * same name methods except the type of event class. See explanation in 79 * nsITextInputProcessor for the detail. 80 */ 81 MOZ_CAN_RUN_SCRIPT nsresult Keydown(const WidgetKeyboardEvent& aKeyboardEvent, 82 uint32_t aKeyFlags, 83 uint32_t* aConsumedFlags = nullptr); 84 nsresult Keyup(const WidgetKeyboardEvent& aKeyboardEvent, uint32_t aKeyFlags, 85 bool* aDoDefault = nullptr); 86 87 /** 88 * GuessCodeNameIndexOfPrintableKeyInUSEnglishLayout() returns CodeNameIndex 89 * of a printable key which is in usual keyboard of the platform and when 90 * active keyboard layout is US-English. 91 * Note that this does not aware of option key mapping on macOS. 92 * 93 * @param aKeyValue The key value. Must be a character which can 94 * be inputted with US-English keyboard layout. 95 * @param aLocation The location of the key. This is important 96 * to distinguish whether the key is in Standard 97 * or Numpad. If this is not some, treated as 98 * Standard. 99 * @return Returns CODE_NAME_INDEX_UNKNOWN if there is 100 * no proper key. 101 */ 102 static CodeNameIndex GuessCodeNameIndexOfPrintableKeyInUSEnglishLayout( 103 const nsAString& aKeyValue, const Maybe<uint32_t>& aLocation); 104 105 /** 106 * GuessKeyCodeOfPrintableKeyInUSEnglishLayout() returns a key code value 107 * of a printable key which is in usual keyboard of the platform and when 108 * active keyboard layout is US-English. 109 * Note that this does not aware of option key mapping on macOS. 110 * 111 * @param aKeyValue The key value. Must be a character which can 112 * be inputted with US-English keyboard layout. 113 * @param aLocation The location of the key. This is important 114 * to distinguish whether the key is in Standard 115 * or Numpad. If this is not some, treated as 116 * Standard. 117 * @return Returns 0 if there is no proper key to input 118 * aKeyValue with US-English keyboard layout. 119 */ 120 static uint32_t GuessKeyCodeOfPrintableKeyInUSEnglishLayout( 121 const nsAString& aKeyValue, const Maybe<uint32_t>& aLocation); 122 123 protected: 124 virtual ~TextInputProcessor(); 125 126 private: 127 bool IsComposing() const; 128 nsresult BeginInputTransactionInternal( 129 mozIDOMWindow* aWindow, nsITextInputProcessorCallback* aCallback, 130 bool aForTests, bool& aSucceeded); 131 MOZ_CAN_RUN_SCRIPT nsresult CommitCompositionInternal( 132 const WidgetKeyboardEvent* aKeyboardEvent = nullptr, 133 uint32_t aKeyFlags = 0, const nsAString* aCommitString = nullptr, 134 bool* aSucceeded = nullptr); 135 MOZ_CAN_RUN_SCRIPT nsresult 136 CancelCompositionInternal(const WidgetKeyboardEvent* aKeyboardEvent = nullptr, 137 uint32_t aKeyFlags = 0); 138 MOZ_CAN_RUN_SCRIPT nsresult 139 KeydownInternal(const WidgetKeyboardEvent& aKeyboardEvent, uint32_t aKeyFlags, 140 bool aAllowToDispatchKeypress, uint32_t& aConsumedFlags); 141 nsresult KeyupInternal(const WidgetKeyboardEvent& aKeyboardEvent, 142 uint32_t aKeyFlags, bool& aDoDefault); 143 nsresult IsValidStateForComposition(); 144 void UnlinkFromTextEventDispatcher(); 145 nsresult PrepareKeyboardEventToDispatch(WidgetKeyboardEvent& aKeyboardEvent, 146 uint32_t aKeyFlags); 147 /** 148 * InitEditCommands() initializes edit commands of aKeyboardEvent. 149 * This must be called only in a content process, and aKeyboardEvent must 150 * be used only for `eKeyPress` event. 151 */ 152 MOZ_CAN_RUN_SCRIPT nsresult 153 InitEditCommands(WidgetKeyboardEvent& aKeyboardEvent) const; 154 155 bool IsValidEventTypeForComposition( 156 const WidgetKeyboardEvent& aKeyboardEvent) const; 157 nsresult PrepareKeyboardEventForComposition( 158 dom::KeyboardEvent* aDOMKeyEvent, uint32_t& aKeyFlags, 159 uint8_t aOptionalArgc, WidgetKeyboardEvent*& aKeyboardEvent); 160 161 struct EventDispatcherResult { 162 nsresult mResult; 163 bool mDoDefault; 164 bool mCanContinue; 165 166 EventDispatcherResult() 167 : mResult(NS_OK), mDoDefault(true), mCanContinue(true) {} 168 }; 169 MOZ_CAN_RUN_SCRIPT EventDispatcherResult MaybeDispatchKeydownForComposition( 170 const WidgetKeyboardEvent* aKeyboardEvent, uint32_t aKeyFlags); 171 EventDispatcherResult MaybeDispatchKeyupForComposition( 172 const WidgetKeyboardEvent* aKeyboardEvent, uint32_t aKeyFlags); 173 174 /** 175 * AutoPendingCompositionResetter guarantees to clear all pending composition 176 * data in its destructor. 177 */ 178 class MOZ_STACK_CLASS AutoPendingCompositionResetter { 179 public: 180 explicit AutoPendingCompositionResetter(TextInputProcessor* aTIP); 181 ~AutoPendingCompositionResetter(); 182 183 private: 184 RefPtr<TextInputProcessor> mTIP; 185 }; 186 187 /** 188 * TextInputProcessor manages modifier state both with .key and .code. 189 * For example, left shift key up shouldn't cause inactivating shift state 190 * while right shift key is being pressed. 191 */ 192 struct ModifierKeyData { 193 // One of modifier key name 194 KeyNameIndex mKeyNameIndex; 195 // Any code name is allowed. 196 CodeNameIndex mCodeNameIndex; 197 // A modifier key flag which is activated by the key. 198 Modifiers mModifier; 199 200 explicit ModifierKeyData(const WidgetKeyboardEvent& aKeyboardEvent); 201 202 bool operator==(const ModifierKeyData& aOther) const { 203 return mKeyNameIndex == aOther.mKeyNameIndex && 204 mCodeNameIndex == aOther.mCodeNameIndex; 205 } 206 }; 207 208 class ModifierKeyDataArray : public nsTArray<ModifierKeyData> { 209 NS_INLINE_DECL_REFCOUNTING(ModifierKeyDataArray) 210 211 public: 212 Modifiers GetActiveModifiers() const; 213 void ActivateModifierKey(const ModifierKeyData& aModifierKeyData); 214 void InactivateModifierKey(const ModifierKeyData& aModifierKeyData); 215 void ToggleModifierKey(const ModifierKeyData& aModifierKeyData); 216 217 private: 218 virtual ~ModifierKeyDataArray() = default; 219 }; 220 221 void EnsureModifierKeyDataArray() { 222 if (mModifierKeyDataArray) { 223 return; 224 } 225 mModifierKeyDataArray = new ModifierKeyDataArray(); 226 } 227 void ActivateModifierKey(const ModifierKeyData& aModifierKeyData) { 228 EnsureModifierKeyDataArray(); 229 mModifierKeyDataArray->ActivateModifierKey(aModifierKeyData); 230 } 231 void InactivateModifierKey(const ModifierKeyData& aModifierKeyData) { 232 if (!mModifierKeyDataArray) { 233 return; 234 } 235 mModifierKeyDataArray->InactivateModifierKey(aModifierKeyData); 236 } 237 void ToggleModifierKey(const ModifierKeyData& aModifierKeyData) { 238 EnsureModifierKeyDataArray(); 239 mModifierKeyDataArray->ToggleModifierKey(aModifierKeyData); 240 } 241 242 TextEventDispatcher* mDispatcher; // [Weak] 243 nsCOMPtr<nsITextInputProcessorCallback> mCallback; 244 RefPtr<ModifierKeyDataArray> mModifierKeyDataArray; 245 246 bool mForTests; 247 }; 248 249 } // namespace mozilla 250 251 #endif // #ifndef mozilla_dom_textinputprocessor_h_