summaryrefslogtreecommitdiffstats
path: root/dom/base/TextInputProcessor.h
blob: 10e04219531969feeb286753b799134fe19f04a4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
/* -*- 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<uint32_t>& 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<uint32_t>& 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<TextInputProcessor> 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<ModifierKeyData> {
    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<nsITextInputProcessorCallback> mCallback;
  RefPtr<ModifierKeyDataArray> mModifierKeyDataArray;

  bool mForTests;
};

}  // namespace mozilla

#endif  // #ifndef mozilla_dom_textinputprocessor_h_