1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et 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 TextInputHandler_h_
8 #define TextInputHandler_h_
9 
10 #include "nsCocoaUtils.h"
11 
12 #import <Carbon/Carbon.h>
13 #import <Cocoa/Cocoa.h>
14 #include "mozView.h"
15 #include "nsString.h"
16 #include "nsCOMPtr.h"
17 #include "nsITimer.h"
18 #include "nsTArray.h"
19 #include "mozilla/BasicEvents.h"
20 #include "mozilla/EventForwards.h"
21 #include "mozilla/TextEventDispatcherListener.h"
22 #include "WritingModes.h"
23 
24 class nsChildView;
25 
26 namespace mozilla {
27 namespace widget {
28 
29 // Key code constants
30 enum {
31   kVK_PC_PrintScreen = kVK_F13,
32   kVK_PC_ScrollLock = kVK_F14,
33   kVK_PC_Pause = kVK_F15,
34 
35   kVK_PC_Insert = kVK_Help,
36   kVK_PC_Backspace = kVK_Delete,
37   kVK_PC_Delete = kVK_ForwardDelete,
38 
39   kVK_PC_ContextMenu = 0x6E,
40 
41   kVK_Powerbook_KeypadEnter = 0x34  // Enter on Powerbook's keyboard is different
42 };
43 
44 /**
45  * TISInputSourceWrapper is a wrapper for the TISInputSourceRef.  If we get the
46  * TISInputSourceRef from InputSourceID, we need to release the CFArray instance
47  * which is returned by TISCreateInputSourceList.  However, when we release the
48  * list, we cannot access the TISInputSourceRef.  So, it's not usable, and it
49  * may cause the memory leak bugs.  nsTISInputSource automatically releases the
50  * list when the instance is destroyed.
51  */
52 class TISInputSourceWrapper {
53  public:
54   static TISInputSourceWrapper& CurrentInputSource();
55   /**
56    * Shutdown() should be called when nobody doesn't need to use this class.
57    */
58   static void Shutdown();
59 
TISInputSourceWrapper()60   TISInputSourceWrapper()
61       : mInputSource{nullptr},
62         mKeyboardLayout{nullptr},
63         mUCKeyboardLayout{nullptr},
64         mIsRTL{0},
65         mOverrideKeyboard{false} {
66     mInputSourceList = nullptr;
67     Clear();
68   }
69 
TISInputSourceWrapper(const char * aID)70   explicit TISInputSourceWrapper(const char* aID)
71       : mInputSource{nullptr},
72         mKeyboardLayout{nullptr},
73         mUCKeyboardLayout{nullptr},
74         mIsRTL{0},
75         mOverrideKeyboard{false} {
76     mInputSourceList = nullptr;
77     InitByInputSourceID(aID);
78   }
79 
TISInputSourceWrapper(SInt32 aLayoutID)80   explicit TISInputSourceWrapper(SInt32 aLayoutID)
81       : mInputSource{nullptr},
82         mKeyboardLayout{nullptr},
83         mUCKeyboardLayout{nullptr},
84         mIsRTL{0},
85         mOverrideKeyboard{false} {
86     mInputSourceList = nullptr;
87     InitByLayoutID(aLayoutID);
88   }
89 
TISInputSourceWrapper(TISInputSourceRef aInputSource)90   explicit TISInputSourceWrapper(TISInputSourceRef aInputSource)
91       : mInputSource{nullptr},
92         mKeyboardLayout{nullptr},
93         mUCKeyboardLayout{nullptr},
94         mIsRTL{0},
95         mOverrideKeyboard{false} {
96     mInputSourceList = nullptr;
97     InitByTISInputSourceRef(aInputSource);
98   }
99 
~TISInputSourceWrapper()100   ~TISInputSourceWrapper() { Clear(); }
101 
102   void InitByInputSourceID(const char* aID);
103   void InitByInputSourceID(const nsString& aID);
104   void InitByInputSourceID(const CFStringRef aID);
105   /**
106    * InitByLayoutID() initializes the keyboard layout by the layout ID.
107    *
108    * @param aLayoutID             An ID of keyboard layout.
109    *                                0: US
110    *                                1: Greek
111    *                                2: German
112    *                                3: Swedish-Pro
113    *                                4: Dvorak-Qwerty Cmd
114    *                                5: Thai
115    *                                6: Arabic
116    *                                7: French
117    *                                8: Hebrew
118    *                                9: Lithuanian
119    *                               10: Norwegian
120    *                               11: Spanish
121    * @param aOverrideKeyboard     When testing set to TRUE, otherwise, set to
122    *                              FALSE.  When TRUE, we use an ANSI keyboard
123    *                              instead of the actual keyboard.
124    */
125   void InitByLayoutID(SInt32 aLayoutID, bool aOverrideKeyboard = false);
126   void InitByCurrentInputSource();
127   void InitByCurrentKeyboardLayout();
128   void InitByCurrentASCIICapableInputSource();
129   void InitByCurrentASCIICapableKeyboardLayout();
130   void InitByCurrentInputMethodKeyboardLayoutOverride();
131   void InitByTISInputSourceRef(TISInputSourceRef aInputSource);
132   void InitByLanguage(CFStringRef aLanguage);
133 
134   /**
135    * If the instance is initialized with a keyboard layout input source,
136    * returns it.
137    * If the instance is initialized with an IME mode input source, the result
138    * references the keyboard layout for the IME mode.  However, this can be
139    * initialized only when the IME mode is actually selected.  I.e, if IME mode
140    * input source is initialized with LayoutID or SourceID, this returns null.
141    */
GetKeyboardLayoutInputSource()142   TISInputSourceRef GetKeyboardLayoutInputSource() const { return mKeyboardLayout; }
143   const UCKeyboardLayout* GetUCKeyboardLayout();
144 
145   bool IsOpenedIMEMode();
146   bool IsIMEMode();
147   bool IsKeyboardLayout();
148 
IsASCIICapable()149   bool IsASCIICapable() {
150     NS_ENSURE_TRUE(mInputSource, false);
151     return GetBoolProperty(kTISPropertyInputSourceIsASCIICapable);
152   }
153 
IsEnabled()154   bool IsEnabled() {
155     NS_ENSURE_TRUE(mInputSource, false);
156     return GetBoolProperty(kTISPropertyInputSourceIsEnabled);
157   }
158 
159   bool GetLanguageList(CFArrayRef& aLanguageList);
160   bool GetPrimaryLanguage(CFStringRef& aPrimaryLanguage);
161   bool GetPrimaryLanguage(nsAString& aPrimaryLanguage);
162 
GetLocalizedName(CFStringRef & aName)163   bool GetLocalizedName(CFStringRef& aName) {
164     NS_ENSURE_TRUE(mInputSource, false);
165     return GetStringProperty(kTISPropertyLocalizedName, aName);
166   }
167 
GetLocalizedName(nsAString & aName)168   bool GetLocalizedName(nsAString& aName) {
169     NS_ENSURE_TRUE(mInputSource, false);
170     return GetStringProperty(kTISPropertyLocalizedName, aName);
171   }
172 
GetInputSourceID(CFStringRef & aID)173   bool GetInputSourceID(CFStringRef& aID) {
174     NS_ENSURE_TRUE(mInputSource, false);
175     return GetStringProperty(kTISPropertyInputSourceID, aID);
176   }
177 
GetInputSourceID(nsAString & aID)178   bool GetInputSourceID(nsAString& aID) {
179     NS_ENSURE_TRUE(mInputSource, false);
180     return GetStringProperty(kTISPropertyInputSourceID, aID);
181   }
182 
GetBundleID(CFStringRef & aBundleID)183   bool GetBundleID(CFStringRef& aBundleID) {
184     NS_ENSURE_TRUE(mInputSource, false);
185     return GetStringProperty(kTISPropertyBundleID, aBundleID);
186   }
187 
GetBundleID(nsAString & aBundleID)188   bool GetBundleID(nsAString& aBundleID) {
189     NS_ENSURE_TRUE(mInputSource, false);
190     return GetStringProperty(kTISPropertyBundleID, aBundleID);
191   }
192 
GetInputSourceType(CFStringRef & aType)193   bool GetInputSourceType(CFStringRef& aType) {
194     NS_ENSURE_TRUE(mInputSource, false);
195     return GetStringProperty(kTISPropertyInputSourceType, aType);
196   }
197 
GetInputSourceType(nsAString & aType)198   bool GetInputSourceType(nsAString& aType) {
199     NS_ENSURE_TRUE(mInputSource, false);
200     return GetStringProperty(kTISPropertyInputSourceType, aType);
201   }
202 
203   bool IsForRTLLanguage();
204   bool IsForJapaneseLanguage();
205   bool IsInitializedByCurrentInputSource();
206 
207   enum {
208     // 40 is an actual result of the ::LMGetKbdType() when we connect an
209     // unknown keyboard and set the keyboard type to ANSI manually on the
210     // set up dialog.
211     eKbdType_ANSI = 40
212   };
213 
214   void Select();
215   void Clear();
216 
217   /**
218    * InitKeyEvent() initializes aKeyEvent for aNativeKeyEvent.
219    *
220    * @param aNativeKeyEvent       A native key event for which you want to
221    *                              dispatch a Gecko key event.
222    * @param aKeyEvent             The result -- a Gecko key event initialized
223    *                              from the native key event.
224    * @param aIsProcessedByIME     true if aNativeKeyEvent has been handled
225    *                              by IME (but except if the composition was
226    *                              started with dead key).
227    * @param aInsertString         If caller expects that the event will cause
228    *                              a character to be input (say in an editor),
229    *                              the caller should set this.  Otherwise,
230    *                              if caller sets null to this, this method will
231    *                              compute the character to be input from
232    *                              characters of aNativeKeyEvent.
233    */
234   void InitKeyEvent(NSEvent* aNativeKeyEvent, WidgetKeyboardEvent& aKeyEvent,
235                     bool aIsProcessedByIME, const nsAString* aInsertString = nullptr);
236 
237   /**
238    * WillDispatchKeyboardEvent() computes aKeyEvent.mAlternativeCharCodes and
239    * recompute aKeyEvent.mCharCode if it's necessary.
240    *
241    * @param aNativeKeyEvent       A native key event for which you want to
242    *                              dispatch a Gecko key event.
243    * @param aInsertString         If caller expects that the event will cause
244    *                              a character to be input (say in an editor),
245    *                              the caller should set this.  Otherwise,
246    *                              if caller sets null to this, this method will
247    *                              compute the character to be input from
248    *                              characters of aNativeKeyEvent.
249    * @param aIndexOfKeypress      Index of the eKeyPress event.  If a key
250    *                              inputs 2 or more characters, eKeyPress events
251    *                              are dispatched for each character.  This is
252    *                              0 for the first eKeyPress event.
253    * @param aKeyEvent             The result -- a Gecko key event initialized
254    *                              from the native key event.  This must be
255    *                              eKeyPress event.
256    */
257   void WillDispatchKeyboardEvent(NSEvent* aNativeKeyEvent, const nsAString* aInsertString,
258                                  uint32_t aIndexOfKeypress, WidgetKeyboardEvent& aKeyEvent);
259 
260   /**
261    * ComputeGeckoKeyCode() returns Gecko keycode for aNativeKeyCode on current
262    * keyboard layout.
263    *
264    * @param aNativeKeyCode        A native keycode.
265    * @param aKbType               A native Keyboard Type value.  Typically,
266    *                              this is a result of ::LMGetKbdType().
267    * @param aCmdIsPressed         TRUE if Cmd key is pressed.  Otherwise, FALSE.
268    * @return                      The computed Gecko keycode.
269    */
270   uint32_t ComputeGeckoKeyCode(UInt32 aNativeKeyCode, UInt32 aKbType, bool aCmdIsPressed);
271 
272   /**
273    * ComputeGeckoKeyNameIndex() returns Gecko key name index for the key.
274    *
275    * @param aNativeKeyCode        A native keycode.
276    */
277   static KeyNameIndex ComputeGeckoKeyNameIndex(UInt32 aNativeKeyCode);
278 
279   /**
280    * ComputeGeckoCodeNameIndex() returns Gecko code name index for the key.
281    *
282    * @param aNativeKeyCode        A native keycode.
283    * @param aKbType               A native Keyboard Type value.  Typically,
284    *                              this is a result of ::LMGetKbdType().
285    */
286   static CodeNameIndex ComputeGeckoCodeNameIndex(UInt32 aNativeKeyCode, UInt32 aKbType);
287 
288   /**
289    * TranslateToChar() checks if aNativeKeyEvent is a dead key.
290    *
291    * @param aNativeKeyEvent       A native key event.
292    * @return                      Returns true if the key event is a dead key
293    *                              event.  Otherwise, false.
294    */
295   bool IsDeadKey(NSEvent* aNativeKeyEvent);
296 
297  protected:
298   /**
299    * TranslateToString() computes the inputted text from the native keyCode,
300    * modifier flags and keyboard type.
301    *
302    * @param aKeyCode              A native keyCode.
303    * @param aModifiers            Combination of native modifier flags.
304    * @param aKbType               A native Keyboard Type value.  Typically,
305    *                              this is a result of ::LMGetKbdType().
306    * @param aStr                  Result, i.e., inputted text.
307    *                              The result can be two or more characters.
308    * @return                      If succeeded, TRUE.  Otherwise, FALSE.
309    *                              Even if TRUE, aStr can be empty string.
310    */
311   bool TranslateToString(UInt32 aKeyCode, UInt32 aModifiers, UInt32 aKbType, nsAString& aStr);
312 
313   /**
314    * TranslateToChar() computes the inputted character from the native keyCode,
315    * modifier flags and keyboard type.  If two or more characters would be
316    * input, this returns 0.
317    *
318    * @param aKeyCode              A native keyCode.
319    * @param aModifiers            Combination of native modifier flags.
320    * @param aKbType               A native Keyboard Type value.  Typically,
321    *                              this is a result of ::LMGetKbdType().
322    * @return                      If succeeded and the result is one character,
323    *                              returns the charCode of it.  Otherwise,
324    *                              returns 0.
325    */
326   uint32_t TranslateToChar(UInt32 aKeyCode, UInt32 aModifiers, UInt32 aKbType);
327 
328   /**
329    * TranslateToChar() checks if aKeyCode with aModifiers is a dead key.
330    *
331    * @param aKeyCode              A native keyCode.
332    * @param aModifiers            Combination of native modifier flags.
333    * @param aKbType               A native Keyboard Type value.  Typically,
334    *                              this is a result of ::LMGetKbdType().
335    * @return                      Returns true if the key with specified
336    *                              modifier state is a dead key.  Otherwise,
337    *                              false.
338    */
339   bool IsDeadKey(UInt32 aKeyCode, UInt32 aModifiers, UInt32 aKbType);
340 
341   /**
342    * ComputeInsertString() computes string to be inserted with the key event.
343    *
344    * @param aNativeKeyEvent     The native key event which causes our keyboard
345    *                            event(s).
346    * @param aKeyEvent           A Gecko key event which was partially
347    *                            initialized with aNativeKeyEvent.
348    * @param aInsertString       The string to be inputting by aNativeKeyEvent.
349    *                            This should be specified by InsertText().
350    *                            In other words, if the key event doesn't cause
351    *                            a call of InsertText(), this can be nullptr.
352    * @param aResult             The string which should be set to charCode of
353    *                            keypress event(s).
354    */
355   void ComputeInsertStringForCharCode(NSEvent* aNativeKeyEvent,
356                                       const WidgetKeyboardEvent& aKeyEvent,
357                                       const nsAString* aInsertString, nsAString& aResult);
358 
359   /**
360    * IsPrintableKeyEvent() returns true if aNativeKeyEvent is caused by
361    * a printable key.  Otherwise, returns false.
362    */
363   bool IsPrintableKeyEvent(NSEvent* aNativeKeyEvent) const;
364 
365   /**
366    * GetKbdType() returns physical keyboard type.
367    */
368   UInt32 GetKbdType() const;
369 
370   bool GetBoolProperty(const CFStringRef aKey);
371   bool GetStringProperty(const CFStringRef aKey, CFStringRef& aStr);
372   bool GetStringProperty(const CFStringRef aKey, nsAString& aStr);
373 
374   TISInputSourceRef mInputSource;
375   TISInputSourceRef mKeyboardLayout;
376   CFArrayRef mInputSourceList;
377   const UCKeyboardLayout* mUCKeyboardLayout;
378   int8_t mIsRTL;
379 
380   bool mOverrideKeyboard;
381 
382   static TISInputSourceWrapper* sCurrentInputSource;
383 };
384 
385 /**
386  * TextInputHandlerBase is a base class of IMEInputHandler and TextInputHandler.
387  * Utility methods should be implemented this level.
388  */
389 
390 class TextInputHandlerBase : public TextEventDispatcherListener {
391  public:
392   /**
393    * Other TextEventDispatcherListener methods should be implemented in
394    * IMEInputHandler.
395    */
396   NS_DECL_ISUPPORTS
397 
398   /**
399    * DispatchEvent() dispatches aEvent on mWidget.
400    *
401    * @param aEvent                An event which you want to dispatch.
402    * @return                      TRUE if the event is consumed by web contents
403    *                              or chrome contents.  Otherwise, FALSE.
404    */
405   bool DispatchEvent(WidgetGUIEvent& aEvent);
406 
407   /**
408    * SetSelection() dispatches eSetSelection event for the aRange.
409    *
410    * @param aRange                The range which will be selected.
411    * @return                      TRUE if setting selection is succeeded and
412    *                              the widget hasn't been destroyed.
413    *                              Otherwise, FALSE.
414    */
415   bool SetSelection(NSRange& aRange);
416 
417   /**
418    * InitKeyEvent() initializes aKeyEvent for aNativeKeyEvent.
419    *
420    * @param aNativeKeyEvent       A native key event for which you want to
421    *                              dispatch a Gecko key event.
422    * @param aKeyEvent             The result -- a Gecko key event initialized
423    *                              from the native key event.
424    * @param aIsProcessedByIME     true if aNativeKeyEvent has been handled
425    *                              by IME (but except if the composition was
426    *                              started with dead key).
427    * @param aInsertString         If caller expects that the event will cause
428    *                              a character to be input (say in an editor),
429    *                              the caller should set this.  Otherwise,
430    *                              if caller sets null to this, this method will
431    *                              compute the character to be input from
432    *                              characters of aNativeKeyEvent.
433    */
434   void InitKeyEvent(NSEvent* aNativeKeyEvent, WidgetKeyboardEvent& aKeyEvent,
435                     bool aIsProcessedByIME, const nsAString* aInsertString = nullptr);
436 
437   /**
438    * SynthesizeNativeKeyEvent() is an implementation of
439    * nsIWidget::SynthesizeNativeKeyEvent().  See the document in nsIWidget.h
440    * for the detail.
441    */
442   nsresult SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout, int32_t aNativeKeyCode,
443                                     uint32_t aModifierFlags, const nsAString& aCharacters,
444                                     const nsAString& aUnmodifiedCharacters);
445 
446   /**
447    * Utility method intended for testing. Attempts to construct a native key
448    * event that would have been generated during an actual key press. This
449    * *does not dispatch* the native event. Instead, it is attached to the
450    * |mNativeKeyEvent| field of the Gecko event that is passed in.
451    * @param aKeyEvent  Gecko key event to attach the native event to
452    */
453   NS_IMETHOD AttachNativeKeyEvent(WidgetKeyboardEvent& aKeyEvent);
454 
455   /**
456    * GetWindowLevel() returns the window level of current focused (in Gecko)
457    * window.  E.g., if an <input> element in XUL panel has focus, this returns
458    * the XUL panel's window level.
459    */
460   NSInteger GetWindowLevel();
461 
462   /**
463    * IsSpecialGeckoKey() checks whether aNativeKeyCode is mapped to a special
464    * Gecko keyCode.  A key is "special" if it isn't used for text input.
465    *
466    * @param aNativeKeyCode        A native keycode.
467    * @return                      If the keycode is mapped to a special key,
468    *                              TRUE.  Otherwise, FALSE.
469    */
470   static bool IsSpecialGeckoKey(UInt32 aNativeKeyCode);
471 
472   /**
473    * EnableSecureEventInput() and DisableSecureEventInput() wrap the Carbon
474    * Event Manager APIs with the same names.  In addition they keep track of
475    * how many times we've called them (in the same process) -- unlike the
476    * Carbon Event Manager APIs, which only keep track of how many times they've
477    * been called from any and all processes.
478    *
479    * The Carbon Event Manager's IsSecureEventInputEnabled() returns whether
480    * secure event input mode is enabled (in any process).  This class's
481    * IsSecureEventInputEnabled() returns whether we've made any calls to
482    * EnableSecureEventInput() that are not (yet) offset by the calls we've
483    * made to DisableSecureEventInput().
484    */
485   static void EnableSecureEventInput();
486   static void DisableSecureEventInput();
487   static bool IsSecureEventInputEnabled();
488 
489   /**
490    * EnsureSecureEventInputDisabled() calls DisableSecureEventInput() until
491    * our call count becomes 0.
492    */
493   static void EnsureSecureEventInputDisabled();
494 
495  public:
496   /**
497    * mWidget must not be destroyed without OnDestroyWidget being called.
498    *
499    * @param aDestroyingWidget     Destroying widget.  This might not be mWidget.
500    * @return                      This result doesn't have any meaning for
501    *                              callers.  When aDstroyingWidget isn't the same
502    *                              as mWidget, FALSE.  Then, inherited methods in
503    *                              sub classes should return from this method
504    *                              without cleaning up.
505    */
506   virtual bool OnDestroyWidget(nsChildView* aDestroyingWidget);
507 
508  protected:
509   // The creator of this instance, client and its text event dispatcher.
510   // These members must not be nullptr after initialized until
511   // OnDestroyWidget() is called.
512   nsChildView* mWidget;  // [WEAK]
513   RefPtr<TextEventDispatcher> mDispatcher;
514 
515   // The native view for mWidget.
516   // This view handles the actual text inputting.
517   NSView<mozView>* mView;  // [STRONG]
518 
519   TextInputHandlerBase(nsChildView* aWidget, NSView<mozView>* aNativeView);
520   virtual ~TextInputHandlerBase();
521 
Destroyed()522   bool Destroyed() { return !mWidget; }
523 
524   /**
525    * mCurrentKeyEvent indicates what key event we are handling.  While
526    * handling a native keydown event, we need to store the event for insertText,
527    * doCommandBySelector and various action message handlers of NSResponder
528    * such as [NSResponder insertNewline:sender].
529    */
530   struct KeyEventState {
531     // Handling native key event
532     NSEvent* mKeyEvent;
533     // String specified by InsertText().  This is not null only during a
534     // call of InsertText().
535     nsAString* mInsertString;
536     // String which are included in [mKeyEvent characters] and already handled
537     // by InsertText() call(s).
538     nsString mInsertedString;
539     // Unique id associated with a keydown / keypress event. It's ok if this
540     // wraps over long periods.
541     uint32_t mUniqueId;
542     // Whether keydown event was dispatched for mKeyEvent.
543     bool mKeyDownDispatched;
544     // Whether keydown event was consumed by web contents or chrome contents.
545     bool mKeyDownHandled;
546     // Whether keypress event was dispatched for mKeyEvent.
547     bool mKeyPressDispatched;
548     // Whether keypress event was consumed by web contents or chrome contents.
549     bool mKeyPressHandled;
550     // Whether the key event causes other key events via IME or something.
551     bool mCausedOtherKeyEvents;
552     // Whether the key event causes composition change or committing
553     // composition.  So, even if InsertText() is called, this may be false
554     // if it dispatches keypress event.
555     bool mCompositionDispatched;
556 
KeyEventStateKeyEventState557     KeyEventState() : mKeyEvent(nullptr), mUniqueId(0) { Clear(); }
558 
559     explicit KeyEventState(NSEvent* aNativeKeyEvent, uint32_t aUniqueId = 0)
mKeyEventKeyEventState560         : mKeyEvent(nullptr), mUniqueId(0) {
561       Clear();
562       Set(aNativeKeyEvent, aUniqueId);
563     }
564 
565     KeyEventState(const KeyEventState& aOther) = delete;
566 
~KeyEventStateKeyEventState567     ~KeyEventState() { Clear(); }
568 
569     void Set(NSEvent* aNativeKeyEvent, uint32_t aUniqueId = 0) {
570       MOZ_ASSERT(aNativeKeyEvent, "aNativeKeyEvent must not be NULL");
571       Clear();
572       mKeyEvent = [aNativeKeyEvent retain];
573       mUniqueId = aUniqueId;
574     }
575 
ClearKeyEventState576     void Clear() {
577       if (mKeyEvent) {
578         [mKeyEvent release];
579         mKeyEvent = nullptr;
580         mUniqueId = 0;
581       }
582       mInsertString = nullptr;
583       mInsertedString.Truncate();
584       mKeyDownDispatched = false;
585       mKeyDownHandled = false;
586       mKeyPressDispatched = false;
587       mKeyPressHandled = false;
588       mCausedOtherKeyEvents = false;
589       mCompositionDispatched = false;
590     }
591 
IsDefaultPreventedKeyEventState592     bool IsDefaultPrevented() const {
593       return mKeyDownHandled || mKeyPressHandled || mCausedOtherKeyEvents || mCompositionDispatched;
594     }
595 
CanDispatchKeyDownEventKeyEventState596     bool CanDispatchKeyDownEvent() const { return !mKeyDownDispatched; }
597 
CanDispatchKeyPressEventKeyEventState598     bool CanDispatchKeyPressEvent() const { return !mKeyPressDispatched && !IsDefaultPrevented(); }
599 
CanHandleCommandKeyEventState600     bool CanHandleCommand() const { return !mKeyDownHandled && !mKeyPressHandled; }
601 
IsProperKeyEventKeyEventState602     bool IsProperKeyEvent(Command aCommand) const {
603       if (NS_WARN_IF(!mKeyEvent)) {
604         return false;
605       }
606       KeyNameIndex keyNameIndex =
607           TISInputSourceWrapper::ComputeGeckoKeyNameIndex([mKeyEvent keyCode]);
608       Modifiers modifiers = nsCocoaUtils::ModifiersForEvent(mKeyEvent) &
609                             (MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT | MODIFIER_META);
610       switch (aCommand) {
611         case Command::InsertLineBreak:
612           return keyNameIndex == KEY_NAME_INDEX_Enter && modifiers == MODIFIER_CONTROL;
613         case Command::InsertParagraph:
614           return keyNameIndex == KEY_NAME_INDEX_Enter && modifiers == MODIFIER_NONE;
615         case Command::DeleteCharBackward:
616           return keyNameIndex == KEY_NAME_INDEX_Backspace && modifiers == MODIFIER_NONE;
617         case Command::DeleteToBeginningOfLine:
618           return keyNameIndex == KEY_NAME_INDEX_Backspace && modifiers == MODIFIER_META;
619         case Command::DeleteWordBackward:
620           return keyNameIndex == KEY_NAME_INDEX_Backspace && modifiers == MODIFIER_ALT;
621         case Command::DeleteCharForward:
622           return keyNameIndex == KEY_NAME_INDEX_Delete && modifiers == MODIFIER_NONE;
623         case Command::DeleteWordForward:
624           return keyNameIndex == KEY_NAME_INDEX_Delete && modifiers == MODIFIER_ALT;
625         case Command::InsertTab:
626           return keyNameIndex == KEY_NAME_INDEX_Tab && modifiers == MODIFIER_NONE;
627         case Command::InsertBacktab:
628           return keyNameIndex == KEY_NAME_INDEX_Tab && modifiers == MODIFIER_SHIFT;
629         case Command::CharNext:
630           return keyNameIndex == KEY_NAME_INDEX_ArrowRight && modifiers == MODIFIER_NONE;
631         case Command::SelectCharNext:
632           return keyNameIndex == KEY_NAME_INDEX_ArrowRight && modifiers == MODIFIER_SHIFT;
633         case Command::WordNext:
634           return keyNameIndex == KEY_NAME_INDEX_ArrowRight && modifiers == MODIFIER_ALT;
635         case Command::SelectWordNext:
636           return keyNameIndex == KEY_NAME_INDEX_ArrowRight &&
637                  modifiers == (MODIFIER_ALT | MODIFIER_SHIFT);
638         case Command::EndLine:
639           return keyNameIndex == KEY_NAME_INDEX_ArrowRight && modifiers == MODIFIER_META;
640         case Command::SelectEndLine:
641           return keyNameIndex == KEY_NAME_INDEX_ArrowRight &&
642                  modifiers == (MODIFIER_META | MODIFIER_SHIFT);
643         case Command::CharPrevious:
644           return keyNameIndex == KEY_NAME_INDEX_ArrowLeft && modifiers == MODIFIER_NONE;
645         case Command::SelectCharPrevious:
646           return keyNameIndex == KEY_NAME_INDEX_ArrowLeft && modifiers == MODIFIER_SHIFT;
647         case Command::WordPrevious:
648           return keyNameIndex == KEY_NAME_INDEX_ArrowLeft && modifiers == MODIFIER_ALT;
649         case Command::SelectWordPrevious:
650           return keyNameIndex == KEY_NAME_INDEX_ArrowLeft &&
651                  modifiers == (MODIFIER_ALT | MODIFIER_SHIFT);
652         case Command::BeginLine:
653           return keyNameIndex == KEY_NAME_INDEX_ArrowLeft && modifiers == MODIFIER_META;
654         case Command::SelectBeginLine:
655           return keyNameIndex == KEY_NAME_INDEX_ArrowLeft &&
656                  modifiers == (MODIFIER_META | MODIFIER_SHIFT);
657         case Command::LinePrevious:
658           return keyNameIndex == KEY_NAME_INDEX_ArrowUp && modifiers == MODIFIER_NONE;
659         case Command::SelectLinePrevious:
660           return keyNameIndex == KEY_NAME_INDEX_ArrowUp && modifiers == MODIFIER_SHIFT;
661         case Command::MoveTop:
662           return keyNameIndex == KEY_NAME_INDEX_ArrowUp && modifiers == MODIFIER_META;
663         case Command::SelectTop:
664           return (keyNameIndex == KEY_NAME_INDEX_ArrowUp &&
665                   modifiers == (MODIFIER_META | MODIFIER_SHIFT)) ||
666                  (keyNameIndex == KEY_NAME_INDEX_Home && modifiers == MODIFIER_SHIFT);
667         case Command::LineNext:
668           return keyNameIndex == KEY_NAME_INDEX_ArrowDown && modifiers == MODIFIER_NONE;
669         case Command::SelectLineNext:
670           return keyNameIndex == KEY_NAME_INDEX_ArrowDown && modifiers == MODIFIER_SHIFT;
671         case Command::MoveBottom:
672           return keyNameIndex == KEY_NAME_INDEX_ArrowDown && modifiers == MODIFIER_META;
673         case Command::SelectBottom:
674           return (keyNameIndex == KEY_NAME_INDEX_ArrowDown &&
675                   modifiers == (MODIFIER_META | MODIFIER_SHIFT)) ||
676                  (keyNameIndex == KEY_NAME_INDEX_End && modifiers == MODIFIER_SHIFT);
677         case Command::ScrollPageUp:
678           return keyNameIndex == KEY_NAME_INDEX_PageUp && modifiers == MODIFIER_NONE;
679         case Command::SelectPageUp:
680           return keyNameIndex == KEY_NAME_INDEX_PageUp && modifiers == MODIFIER_SHIFT;
681         case Command::ScrollPageDown:
682           return keyNameIndex == KEY_NAME_INDEX_PageDown && modifiers == MODIFIER_NONE;
683         case Command::SelectPageDown:
684           return keyNameIndex == KEY_NAME_INDEX_PageDown && modifiers == MODIFIER_SHIFT;
685         case Command::ScrollBottom:
686           return keyNameIndex == KEY_NAME_INDEX_End && modifiers == MODIFIER_NONE;
687         case Command::ScrollTop:
688           return keyNameIndex == KEY_NAME_INDEX_Home && modifiers == MODIFIER_NONE;
689         case Command::CancelOperation:
690           return (keyNameIndex == KEY_NAME_INDEX_Escape &&
691                   (modifiers == MODIFIER_NONE || modifiers == MODIFIER_SHIFT)) ||
692                  ([mKeyEvent keyCode] == kVK_ANSI_Period && modifiers == MODIFIER_META);
693         case Command::Complete:
694           return keyNameIndex == KEY_NAME_INDEX_Escape &&
695                  (modifiers == MODIFIER_ALT || modifiers == (MODIFIER_ALT | MODIFIER_SHIFT));
696         default:
697           return false;
698       }
699     }
700 
701     void InitKeyEvent(TextInputHandlerBase* aHandler, WidgetKeyboardEvent& aKeyEvent,
702                       bool aIsProcessedByIME);
703 
704     /**
705      * GetUnhandledString() returns characters of the event which have not been
706      * handled with InsertText() yet. For example, if there is a composition
707      * caused by a dead key press like '`' and it's committed by some key
708      * combinations like |Cmd+v|, then, the |v|'s KeyDown event's |characters|
709      * is |`v|.  Then, after |`| is committed with a call of InsertString(),
710      * this returns only 'v'.
711      */
712     void GetUnhandledString(nsAString& aUnhandledString) const;
713   };
714 
715   /**
716    * Helper classes for guaranteeing cleaning mCurrentKeyEvent
717    */
718   class AutoKeyEventStateCleaner {
719    public:
AutoKeyEventStateCleaner(TextInputHandlerBase * aHandler)720     explicit AutoKeyEventStateCleaner(TextInputHandlerBase* aHandler) : mHandler(aHandler) {}
721 
~AutoKeyEventStateCleaner()722     ~AutoKeyEventStateCleaner() { mHandler->RemoveCurrentKeyEvent(); }
723 
724    private:
725     RefPtr<TextInputHandlerBase> mHandler;
726   };
727 
728   class MOZ_STACK_CLASS AutoInsertStringClearer {
729    public:
AutoInsertStringClearer(KeyEventState * aState)730     explicit AutoInsertStringClearer(KeyEventState* aState) : mState(aState) {}
731     ~AutoInsertStringClearer();
732 
733    private:
734     KeyEventState* mState;
735   };
736 
737   /**
738    * mCurrentKeyEvents stores all key events which are being processed.
739    * When we call interpretKeyEvents, IME may generate other key events.
740    * mCurrentKeyEvents[0] is the latest key event.
741    */
742   nsTArray<KeyEventState*> mCurrentKeyEvents;
743 
744   /**
745    * mFirstKeyEvent must be used for first key event.  This member prevents
746    * memory fragmentation for most key events.
747    */
748   KeyEventState mFirstKeyEvent;
749 
750   /**
751    * PushKeyEvent() adds the current key event to mCurrentKeyEvents.
752    */
753   KeyEventState* PushKeyEvent(NSEvent* aNativeKeyEvent, uint32_t aUniqueId = 0) {
754     uint32_t nestCount = mCurrentKeyEvents.Length();
755     for (uint32_t i = 0; i < nestCount; i++) {
756       // When the key event is caused by another key event, all key events
757       // which are being handled should be marked as "consumed".
758       mCurrentKeyEvents[i]->mCausedOtherKeyEvents = true;
759     }
760 
761     KeyEventState* keyEvent = nullptr;
762     if (nestCount == 0) {
763       mFirstKeyEvent.Set(aNativeKeyEvent, aUniqueId);
764       keyEvent = &mFirstKeyEvent;
765     } else {
766       keyEvent = new KeyEventState(aNativeKeyEvent, aUniqueId);
767     }
768     return *mCurrentKeyEvents.AppendElement(keyEvent);
769   }
770 
771   /**
772    * RemoveCurrentKeyEvent() removes the current key event from
773    * mCurrentKeyEvents.
774    */
RemoveCurrentKeyEvent()775   void RemoveCurrentKeyEvent() {
776     NS_ASSERTION(mCurrentKeyEvents.Length() > 0, "RemoveCurrentKeyEvent() is called unexpectedly");
777     KeyEventState* keyEvent = mCurrentKeyEvents.PopLastElement();
778     if (keyEvent == &mFirstKeyEvent) {
779       keyEvent->Clear();
780     } else {
781       delete keyEvent;
782     }
783   }
784 
785   /**
786    * GetCurrentKeyEvent() returns current processing key event.
787    */
GetCurrentKeyEvent()788   KeyEventState* GetCurrentKeyEvent() {
789     if (mCurrentKeyEvents.Length() == 0) {
790       return nullptr;
791     }
792     return mCurrentKeyEvents[mCurrentKeyEvents.Length() - 1];
793   }
794 
795   struct KeyboardLayoutOverride final {
796     int32_t mKeyboardLayout;
797     bool mOverrideEnabled;
798 
KeyboardLayoutOverridefinal799     KeyboardLayoutOverride() : mKeyboardLayout(0), mOverrideEnabled(false) {}
800   };
801 
KeyboardLayoutOverrideRef()802   const KeyboardLayoutOverride& KeyboardLayoutOverrideRef() const { return mKeyboardOverride; }
803 
804   /**
805    * IsPrintableChar() checks whether the unicode character is
806    * a non-printable ASCII character or not.  Note that this returns
807    * TRUE even if aChar is a non-printable UNICODE character.
808    *
809    * @param aChar                 A unicode character.
810    * @return                      TRUE if aChar is a printable ASCII character
811    *                              or a unicode character.  Otherwise, i.e,
812    *                              if aChar is a non-printable ASCII character,
813    *                              FALSE.
814    */
815   static bool IsPrintableChar(char16_t aChar);
816 
817   /**
818    * IsNormalCharInputtingEvent() checks whether aNativeEvent causes text input.
819    *
820    * @param aNativeEvent          A key event.
821    * @return                      TRUE if the key event causes text input.
822    *                              Otherwise, FALSE.
823    */
824   static bool IsNormalCharInputtingEvent(NSEvent* aNativeEvent);
825 
826   /**
827    * IsModifierKey() checks whether the native keyCode is for a modifier key.
828    *
829    * @param aNativeKeyCode        A native keyCode.
830    * @return                      TRUE if aNativeKeyCode is for a modifier key.
831    *                              Otherwise, FALSE.
832    */
833   static bool IsModifierKey(UInt32 aNativeKeyCode);
834 
835  private:
836   KeyboardLayoutOverride mKeyboardOverride;
837 
838   static int32_t sSecureEventInputCount;
839 };
840 
841 /**
842  * IMEInputHandler manages:
843  *   1. The IME/keyboard layout statement of nsChildView.
844  *   2. The IME composition statement of nsChildView.
845  * And also provides the methods which controls the current IME transaction of
846  * the instance.
847  *
848  * Note that an nsChildView handles one or more NSView's events.  E.g., even if
849  * a text editor on XUL panel element, the input events handled on the parent
850  * (or its ancestor) widget handles it (the native focus is set to it).  The
851  * actual focused view is notified by OnFocusChangeInGecko.
852  */
853 
854 class IMEInputHandler : public TextInputHandlerBase {
855  public:
856   // TextEventDispatcherListener methods
857   NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
858                        const IMENotification& aNotification) override;
859   NS_IMETHOD_(IMENotificationRequests) GetIMENotificationRequests() override;
860   NS_IMETHOD_(void) OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher) override;
861   NS_IMETHOD_(void)
862   WillDispatchKeyboardEvent(TextEventDispatcher* aTextEventDispatcher,
863                             WidgetKeyboardEvent& aKeyboardEvent, uint32_t aIndexOfKeypress,
864                             void* aData) override;
865 
866  public:
867   virtual bool OnDestroyWidget(nsChildView* aDestroyingWidget) override;
868 
869   virtual void OnFocusChangeInGecko(bool aFocus);
870 
871   void OnSelectionChange(const IMENotification& aIMENotification);
872   void OnLayoutChange();
873 
874   /**
875    * Call [NSTextInputContext handleEvent] for mouse event support of IME
876    */
877   bool OnHandleEvent(NSEvent* aEvent);
878 
879   /**
880    * SetMarkedText() is a handler of setMarkedText of NSTextInput.
881    *
882    * @param aAttrString           This mut be an instance of NSAttributedString.
883    *                              If the aString parameter to
884    *                              [ChildView setMarkedText:setSelectedRange:]
885    *                              isn't an instance of NSAttributedString,
886    *                              create an NSAttributedString from it and pass
887    *                              that instead.
888    * @param aSelectedRange        Current selected range (or caret position).
889    * @param aReplacementRange     The range which will be replaced with the
890    *                              aAttrString instead of current marked range.
891    */
892   void SetMarkedText(NSAttributedString* aAttrString, NSRange& aSelectedRange,
893                      NSRange* aReplacementRange = nullptr);
894 
895   /**
896    * GetAttributedSubstringFromRange() returns an NSAttributedString instance
897    * which is allocated as autorelease for aRange.
898    *
899    * @param aRange                The range of string which you want.
900    * @param aActualRange          The actual range of the result.
901    * @return                      The string in aRange.  If the string is empty,
902    *                              this returns nil.  If succeeded, this returns
903    *                              an instance which is allocated as autorelease.
904    *                              If this has some troubles, returns nil.
905    */
906   NSAttributedString* GetAttributedSubstringFromRange(NSRange& aRange,
907                                                       NSRange* aActualRange = nullptr);
908 
909   /**
910    * SelectedRange() returns current selected range.
911    *
912    * @return                      If an editor has focus, this returns selection
913    *                              range in the editor.  Otherwise, this returns
914    *                              selection range  in the focused document.
915    */
916   NSRange SelectedRange();
917 
918   /**
919    * DrawsVerticallyForCharacterAtIndex() returns whether the character at
920    * the given index is being rendered vertically.
921    *
922    * @param aCharIndex            The character offset to query.
923    *
924    * @return                      True if writing-mode is vertical at the given
925    *                              character offset; otherwise false.
926    */
927   bool DrawsVerticallyForCharacterAtIndex(uint32_t aCharIndex);
928 
929   /**
930    * FirstRectForCharacterRange() returns first *character* rect in the range.
931    * Cocoa needs the first line rect in the range, but we cannot compute it
932    * on current implementation.
933    *
934    * @param aRange                A range of text to examine.  Its position is
935    *                              an offset from the beginning of the focused
936    *                              editor or document.
937    * @param aActualRange          If this is not null, this returns the actual
938    *                              range used for computing the result.
939    * @return                      An NSRect containing the first character in
940    *                              aRange, in screen coordinates.
941    *                              If the length of aRange is 0, the width will
942    *                              be 0.
943    */
944   NSRect FirstRectForCharacterRange(NSRange& aRange, NSRange* aActualRange = nullptr);
945 
946   /**
947    * CharacterIndexForPoint() returns an offset of a character at aPoint.
948    * XXX This isn't implemented, always returns 0.
949    *
950    * @param                       The point in screen coordinates.
951    * @return                      The offset of the character at aPoint from
952    *                              the beginning of the focused editor or
953    *                              document.
954    */
955   NSUInteger CharacterIndexForPoint(NSPoint& aPoint);
956 
957   /**
958    * GetValidAttributesForMarkedText() returns attributes which we support.
959    *
960    * @return                      Always empty array for now.
961    */
962   NSArray* GetValidAttributesForMarkedText();
963 
964   bool HasMarkedText();
965   NSRange MarkedRange();
966 
IsIMEComposing()967   bool IsIMEComposing() { return mIsIMEComposing; }
IsDeadKeyComposing()968   bool IsDeadKeyComposing() { return mIsDeadKeyComposing; }
969   bool IsIMEOpened();
IsIMEEnabled()970   bool IsIMEEnabled() { return mIsIMEEnabled; }
IsASCIICapableOnly()971   bool IsASCIICapableOnly() { return mIsASCIICapableOnly; }
IsEditableContent()972   bool IsEditableContent() const { return mIsIMEEnabled || mIsASCIICapableOnly; }
IgnoreIMECommit()973   bool IgnoreIMECommit() { return mIgnoreIMECommit; }
974 
975   void CommitIMEComposition();
976   void CancelIMEComposition();
977 
978   void EnableIME(bool aEnableIME);
979   void SetIMEOpenState(bool aOpen);
980   void SetASCIICapableOnly(bool aASCIICapableOnly);
981 
982   /**
983    * True if OSX believes that our view has keyboard focus.
984    */
985   bool IsFocused();
986 
987   static CFArrayRef CreateAllIMEModeList();
988   static void DebugPrintAllIMEModes();
989 
990   // Don't use ::TSMGetActiveDocument() API directly, the document may not
991   // be what you want.
992   static TSMDocumentID GetCurrentTSMDocumentID();
993 
994  protected:
995   // We cannot do some jobs in the given stack by some reasons.
996   // Following flags and the timer provide the execution pending mechanism,
997   // See the comment in nsCocoaTextInputHandler.mm.
998   nsCOMPtr<nsITimer> mTimer;
999   enum { kNotifyIMEOfFocusChangeInGecko = 1, kSyncASCIICapableOnly = 2 };
1000   uint32_t mPendingMethods;
1001 
1002   IMEInputHandler(nsChildView* aWidget, NSView<mozView>* aNativeView);
1003   virtual ~IMEInputHandler();
1004 
1005   void ResetTimer();
1006 
1007   virtual void ExecutePendingMethods();
1008 
1009   /**
1010    * InsertTextAsCommittingComposition() commits current composition.  If there
1011    * is no composition, this starts a composition and commits it immediately.
1012    *
1013    * @param aAttrString           A string which is committed.
1014    * @param aReplacementRange     The range which will be replaced with the
1015    *                              aAttrString instead of current selection.
1016    */
1017   void InsertTextAsCommittingComposition(NSAttributedString* aAttrString,
1018                                          NSRange* aReplacementRange);
1019 
1020   /**
1021    * MaybeDispatchCurrentKeydownEvent() dispatches eKeyDown event for current
1022    * key event.  If eKeyDown for current key event has already been dispatched,
1023    * this does nothing.
1024    *
1025    * @param aIsProcessedByIME   true if current key event is handled by IME.
1026    * @return                    true if the caller can continue to handle
1027    *                            current key event.  Otherwise, false.  E.g.,
1028    *                            focus is moved, the widget has been destroyed
1029    *                            or something.
1030    */
1031   bool MaybeDispatchCurrentKeydownEvent(bool aIsProcessedByIME);
1032 
1033  private:
1034   // If mIsIMEComposing is true, the composition string is stored here.
1035   NSString* mIMECompositionString;
1036   // If mIsIMEComposing is true, the start offset of the composition string.
1037   uint32_t mIMECompositionStart;
1038 
1039   NSRange mMarkedRange;
1040   NSRange mSelectedRange;
1041 
1042   NSRange mRangeForWritingMode;  // range within which mWritingMode applies
1043   mozilla::WritingMode mWritingMode;
1044 
1045   bool mIsIMEComposing;
1046   // If the composition started with dead key, mIsDeadKeyComposing is set to
1047   // true.
1048   bool mIsDeadKeyComposing;
1049   bool mIsIMEEnabled;
1050   bool mIsASCIICapableOnly;
1051   bool mIgnoreIMECommit;
1052   bool mIMEHasFocus;
1053 
1054   void KillIMEComposition();
1055   void SendCommittedText(NSString* aString);
1056   void OpenSystemPreferredLanguageIME();
1057 
1058   // Pending methods
1059   void NotifyIMEOfFocusChangeInGecko();
1060   void SyncASCIICapableOnly();
1061 
1062   static bool sStaticMembersInitialized;
1063   static CFStringRef sLatestIMEOpenedModeInputSourceID;
1064   static void InitStaticMembers();
1065   static void OnCurrentTextInputSourceChange(CFNotificationCenterRef aCenter, void* aObserver,
1066                                              CFStringRef aName, const void* aObject,
1067                                              CFDictionaryRef aUserInfo);
1068 
1069   static void FlushPendingMethods(nsITimer* aTimer, void* aClosure);
1070 
1071   /**
1072    * ConvertToTextRangeStyle converts the given native underline style to
1073    * our defined text range type.
1074    *
1075    * @param aUnderlineStyle       NSUnderlineStyleSingle or
1076    *                              NSUnderlineStyleThick.
1077    * @param aSelectedRange        Current selected range (or caret position).
1078    * @return                      NS_TEXTRANGE_*.
1079    */
1080   TextRangeType ConvertToTextRangeType(uint32_t aUnderlineStyle, NSRange& aSelectedRange);
1081 
1082   /**
1083    * GetRangeCount() computes the range count of aAttrString.
1084    *
1085    * @param aAttrString           An NSAttributedString instance whose number of
1086    *                              NSUnderlineStyleAttributeName ranges you with
1087    *                              to know.
1088    * @return                      The count of NSUnderlineStyleAttributeName
1089    *                              ranges in aAttrString.
1090    */
1091   uint32_t GetRangeCount(NSAttributedString* aString);
1092 
1093   /**
1094    * CreateTextRangeArray() returns text ranges for clauses and/or caret.
1095    *
1096    * @param aAttrString           An NSAttributedString instance which indicates
1097    *                              current composition string.
1098    * @param aSelectedRange        Current selected range (or caret position).
1099    * @return                      The result is set to the
1100    *                              NSUnderlineStyleAttributeName ranges in
1101    *                              aAttrString.
1102    */
1103   already_AddRefed<mozilla::TextRangeArray> CreateTextRangeArray(NSAttributedString* aAttrString,
1104                                                                  NSRange& aSelectedRange);
1105 
1106   /**
1107    * DispatchCompositionStartEvent() dispatches a compositionstart event and
1108    * initializes the members indicating composition state.
1109    *
1110    * @return                      true if it can continues handling composition.
1111    *                              Otherwise, e.g., canceled by the web page,
1112    *                              this returns false.
1113    */
1114   bool DispatchCompositionStartEvent();
1115 
1116   /**
1117    * DispatchCompositionChangeEvent() dispatches a compositionchange event on
1118    * mWidget and modifies the members indicating composition state.
1119    *
1120    * @param aText                 User text input.
1121    * @param aAttrString           An NSAttributedString instance which indicates
1122    *                              current composition string.
1123    * @param aSelectedRange        Current selected range (or caret position).
1124    *
1125    * @return                      true if it can continues handling composition.
1126    *                              Otherwise, e.g., canceled by the web page,
1127    *                              this returns false.
1128    */
1129   bool DispatchCompositionChangeEvent(const nsString& aText, NSAttributedString* aAttrString,
1130                                       NSRange& aSelectedRange);
1131 
1132   /**
1133    * DispatchCompositionCommitEvent() dispatches a compositioncommit event or
1134    * compositioncommitasis event.  If aCommitString is null, dispatches
1135    * compositioncommitasis event.  I.e., if aCommitString is null, this
1136    * commits the composition with the last data.  Otherwise, commits the
1137    * composition with aCommitString value.
1138    *
1139    * @return                      true if the widget isn't destroyed.
1140    *                              Otherwise, false.
1141    */
1142   bool DispatchCompositionCommitEvent(const nsAString* aCommitString = nullptr);
1143 
1144   // The focused IME handler.  Please note that the handler might lost the
1145   // actual focus by deactivating the application.  If we are active, this
1146   // must have the actual focused handle.
1147   // We cannot access to the NSInputManager during we aren't active, so, the
1148   // focused handler can have an IME transaction even if we are deactive.
1149   static IMEInputHandler* sFocusedIMEHandler;
1150 
1151   static bool sCachedIsForRTLLangage;
1152 };
1153 
1154 /**
1155  * TextInputHandler implements the NSTextInput protocol.
1156  */
1157 class TextInputHandler : public IMEInputHandler {
1158  public:
1159   static NSUInteger sLastModifierState;
1160 
1161   static CFArrayRef CreateAllKeyboardLayoutList();
1162   static void DebugPrintAllKeyboardLayouts();
1163 
1164   TextInputHandler(nsChildView* aWidget, NSView<mozView>* aNativeView);
1165   virtual ~TextInputHandler();
1166 
1167   /**
1168    * KeyDown event handler.
1169    *
1170    * @param aNativeEvent          A native NSEventTypeKeyDown event.
1171    * @param aUniqueId             A unique ID for the event.
1172    * @return                      TRUE if the event is dispatched to web
1173    *                              contents or chrome contents. Otherwise, FALSE.
1174    */
1175   bool HandleKeyDownEvent(NSEvent* aNativeEvent, uint32_t aUniqueId);
1176 
1177   /**
1178    * KeyUp event handler.
1179    *
1180    * @param aNativeEvent          A native NSEventTypeKeyUp event.
1181    */
1182   void HandleKeyUpEvent(NSEvent* aNativeEvent);
1183 
1184   /**
1185    * FlagsChanged event handler.
1186    *
1187    * @param aNativeEvent          A native NSEventTypeFlagsChanged event.
1188    */
1189   void HandleFlagsChanged(NSEvent* aNativeEvent);
1190 
1191   /**
1192    * Insert the string to content.  I.e., this is a text input event handler.
1193    * If this is called during keydown event handling, this may dispatch a
1194    * eKeyPress event.  If this is called during composition, this commits
1195    * the composition by the aAttrString.
1196    *
1197    * @param aAttrString           An inserted string.
1198    * @param aReplacementRange     The range which will be replaced with the
1199    *                              aAttrString instead of current selection.
1200    */
1201   void InsertText(NSAttributedString* aAttrString, NSRange* aReplacementRange = nullptr);
1202 
1203   /**
1204    * Handles aCommand.  This may cause dispatching an eKeyPress event.
1205    *
1206    * @param aCommand    The command which receives from Cocoa.
1207    * @return            true if this handles the command even if it does
1208    *                    nothing actually.  Otherwise, false.
1209    */
1210   bool HandleCommand(Command aCommand);
1211 
1212   /**
1213    * doCommandBySelector event handler.
1214    *
1215    * @param aSelector             A selector of the command.
1216    * @return                      TRUE if the command is consumed.  Otherwise,
1217    *                              FALSE.
1218    */
1219   bool DoCommandBySelector(const char* aSelector);
1220 
1221   /**
1222    * KeyPressWasHandled() checks whether keypress event was handled or not.
1223    *
1224    * @return                      TRUE if keypress event for latest native key
1225    *                              event was handled.  Otherwise, FALSE.
1226    *                              If this handler isn't handling any key events,
1227    *                              always returns FALSE.
1228    */
KeyPressWasHandled()1229   bool KeyPressWasHandled() {
1230     KeyEventState* currentKeyEvent = GetCurrentKeyEvent();
1231     return currentKeyEvent && currentKeyEvent->mKeyPressHandled;
1232   }
1233 
1234  protected:
1235   // Stores the association of device dependent modifier flags with a modifier
1236   // keyCode.  Being device dependent, this association may differ from one kind
1237   // of hardware to the next.
1238   struct ModifierKey {
1239     NSUInteger flags;
1240     unsigned short keyCode;
1241 
ModifierKeyModifierKey1242     ModifierKey(NSUInteger aFlags, unsigned short aKeyCode) : flags(aFlags), keyCode(aKeyCode) {}
1243 
GetDeviceDependentFlagsModifierKey1244     NSUInteger GetDeviceDependentFlags() const {
1245       return (flags & ~NSEventModifierFlagDeviceIndependentFlagsMask);
1246     }
1247 
GetDeviceIndependentFlagsModifierKey1248     NSUInteger GetDeviceIndependentFlags() const {
1249       return (flags & NSEventModifierFlagDeviceIndependentFlagsMask);
1250     }
1251   };
1252   typedef nsTArray<ModifierKey> ModifierKeyArray;
1253   ModifierKeyArray mModifierKeys;
1254 
1255   /**
1256    * GetModifierKeyForNativeKeyCode() returns the stored ModifierKey for
1257    * the key.
1258    */
1259   const ModifierKey* GetModifierKeyForNativeKeyCode(unsigned short aKeyCode) const;
1260 
1261   /**
1262    * GetModifierKeyForDeviceDependentFlags() returns the stored ModifierKey for
1263    * the device dependent flags.
1264    */
1265   const ModifierKey* GetModifierKeyForDeviceDependentFlags(NSUInteger aFlags) const;
1266 
1267   /**
1268    * DispatchKeyEventForFlagsChanged() dispatches keydown event or keyup event
1269    * for the aNativeEvent.
1270    *
1271    * @param aNativeEvent          A native flagschanged event which you want to
1272    *                              dispatch our key event for.
1273    * @param aDispatchKeyDown      TRUE if you want to dispatch a keydown event.
1274    *                              Otherwise, i.e., to dispatch keyup event,
1275    *                              FALSE.
1276    */
1277   void DispatchKeyEventForFlagsChanged(NSEvent* aNativeEvent, bool aDispatchKeyDown);
1278 };
1279 
1280 }  // namespace widget
1281 }  // namespace mozilla
1282 
1283 #endif  // TextInputHandler_h_
1284