widget/cocoa/TextInputHandler.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     7 #ifndef TextInputHandler_h_
     8 #define TextInputHandler_h_
    10 #include "nsCocoaUtils.h"
    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 "npapi.h"
    19 #include "nsTArray.h"
    20 #include "mozilla/EventForwards.h"
    22 class nsChildView;
    24 namespace mozilla {
    25 namespace widget {
    27 // Key code constants
    28 enum
    29 {
    30   kVK_RightCommand    = 0x36, // right command key
    32   kVK_PC_PrintScreen     = kVK_F13,
    33   kVK_PC_ScrollLock      = kVK_F14,
    34   kVK_PC_Pause           = kVK_F15,
    36   kVK_PC_Insert          = kVK_Help,
    37   kVK_PC_Backspace       = kVK_Delete,
    38   kVK_PC_Delete          = kVK_ForwardDelete,
    40   kVK_PC_ContextMenu     = 0x6E,
    42   kVK_Powerbook_KeypadEnter = 0x34  // Enter on Powerbook's keyboard is different
    43 };
    45 /**
    46  * TISInputSourceWrapper is a wrapper for the TISInputSourceRef.  If we get the
    47  * TISInputSourceRef from InputSourceID, we need to release the CFArray instance
    48  * which is returned by TISCreateInputSourceList.  However, when we release the
    49  * list, we cannot access the TISInputSourceRef.  So, it's not usable, and it
    50  * may cause the memory leak bugs.  nsTISInputSource automatically releases the
    51  * list when the instance is destroyed.
    52  */
    53 class TISInputSourceWrapper
    54 {
    55 public:
    56   static TISInputSourceWrapper& CurrentInputSource();
    58   TISInputSourceWrapper()
    59   {
    60     mInputSourceList = nullptr;
    61     Clear();
    62   }
    64   TISInputSourceWrapper(const char* aID)
    65   {
    66     mInputSourceList = nullptr;
    67     InitByInputSourceID(aID);
    68   }
    70   TISInputSourceWrapper(SInt32 aLayoutID)
    71   {
    72     mInputSourceList = nullptr;
    73     InitByLayoutID(aLayoutID);
    74   }
    76   TISInputSourceWrapper(TISInputSourceRef aInputSource)
    77   {
    78     mInputSourceList = nullptr;
    79     InitByTISInputSourceRef(aInputSource);
    80   }
    82   ~TISInputSourceWrapper() { Clear(); }
    84   void InitByInputSourceID(const char* aID);
    85   void InitByInputSourceID(const nsAFlatString &aID);
    86   void InitByInputSourceID(const CFStringRef aID);
    87   /**
    88    * InitByLayoutID() initializes the keyboard layout by the layout ID.
    89    *
    90    * @param aLayoutID             An ID of keyboard layout.
    91    *                                0: US
    92    *                                1: Greek
    93    *                                2: German
    94    *                                3: Swedish-Pro
    95    *                                4: Dvorak-Qwerty Cmd
    96    *                                5: Thai
    97    *                                6: Arabic
    98    *                                7: French
    99    *                                8: Hebrew
   100    *                                9: Lithuanian
   101    *                               10: Norwegian
   102    *                               11: Spanish
   103    * @param aOverrideKeyboard     When testing set to TRUE, otherwise, set to
   104    *                              FALSE.  When TRUE, we use an ANSI keyboard
   105    *                              instead of the actual keyboard.
   106    */
   107   void InitByLayoutID(SInt32 aLayoutID, bool aOverrideKeyboard = false);
   108   void InitByCurrentInputSource();
   109   void InitByCurrentKeyboardLayout();
   110   void InitByCurrentASCIICapableInputSource();
   111   void InitByCurrentASCIICapableKeyboardLayout();
   112   void InitByCurrentInputMethodKeyboardLayoutOverride();
   113   void InitByTISInputSourceRef(TISInputSourceRef aInputSource);
   114   void InitByLanguage(CFStringRef aLanguage);
   116   /**
   117    * If the instance is initialized with a keyboard layout input source,
   118    * returns it.
   119    * If the instance is initialized with an IME mode input source, the result
   120    * references the keyboard layout for the IME mode.  However, this can be
   121    * initialized only when the IME mode is actually selected.  I.e, if IME mode
   122    * input source is initialized with LayoutID or SourceID, this returns null.
   123    */
   124   TISInputSourceRef GetKeyboardLayoutInputSource() const
   125   {
   126     return mKeyboardLayout;
   127   }
   128   const UCKeyboardLayout* GetUCKeyboardLayout();
   130   bool IsOpenedIMEMode();
   131   bool IsIMEMode();
   132   bool IsKeyboardLayout();
   134   bool IsASCIICapable()
   135   {
   136     NS_ENSURE_TRUE(mInputSource, false);
   137     return GetBoolProperty(kTISPropertyInputSourceIsASCIICapable);
   138   }
   140   bool IsEnabled()
   141   {
   142     NS_ENSURE_TRUE(mInputSource, false);
   143     return GetBoolProperty(kTISPropertyInputSourceIsEnabled);
   144   }
   146   bool GetLanguageList(CFArrayRef &aLanguageList);
   147   bool GetPrimaryLanguage(CFStringRef &aPrimaryLanguage);
   148   bool GetPrimaryLanguage(nsAString &aPrimaryLanguage);
   150   bool GetLocalizedName(CFStringRef &aName)
   151   {
   152     NS_ENSURE_TRUE(mInputSource, false);
   153     return GetStringProperty(kTISPropertyLocalizedName, aName);
   154   }
   156   bool GetLocalizedName(nsAString &aName)
   157   {
   158     NS_ENSURE_TRUE(mInputSource, false);
   159     return GetStringProperty(kTISPropertyLocalizedName, aName);
   160   }
   162   bool GetInputSourceID(CFStringRef &aID)
   163   {
   164     NS_ENSURE_TRUE(mInputSource, false);
   165     return GetStringProperty(kTISPropertyInputSourceID, aID);
   166   }
   168   bool GetInputSourceID(nsAString &aID)
   169   {
   170     NS_ENSURE_TRUE(mInputSource, false);
   171     return GetStringProperty(kTISPropertyInputSourceID, aID);
   172   }
   174   bool GetBundleID(CFStringRef &aBundleID)
   175   {
   176     NS_ENSURE_TRUE(mInputSource, false);
   177     return GetStringProperty(kTISPropertyBundleID, aBundleID);
   178   }
   180   bool GetBundleID(nsAString &aBundleID)
   181   {
   182     NS_ENSURE_TRUE(mInputSource, false);
   183     return GetStringProperty(kTISPropertyBundleID, aBundleID);
   184   }
   186   bool GetInputSourceType(CFStringRef &aType)
   187   {
   188     NS_ENSURE_TRUE(mInputSource, false);
   189     return GetStringProperty(kTISPropertyInputSourceType, aType);
   190   }
   192   bool GetInputSourceType(nsAString &aType)
   193   {
   194     NS_ENSURE_TRUE(mInputSource, false);
   195     return GetStringProperty(kTISPropertyInputSourceType, aType);
   196   }
   198   bool IsForRTLLanguage();
   199   bool IsInitializedByCurrentInputSource();
   201   enum {
   202     // 40 is an actual result of the ::LMGetKbdType() when we connect an
   203     // unknown keyboard and set the keyboard type to ANSI manually on the
   204     // set up dialog.
   205     eKbdType_ANSI = 40
   206   };
   208   void Select();
   209   void Clear();
   211   /**
   212    * InitKeyEvent() initializes aKeyEvent for aNativeKeyEvent.
   213    *
   214    * @param aNativeKeyEvent       A native key event for which you want to
   215    *                              dispatch a Gecko key event.
   216    * @param aKeyEvent             The result -- a Gecko key event initialized
   217    *                              from the native key event.
   218    * @param aInsertString         If caller expects that the event will cause
   219    *                              a character to be input (say in an editor),
   220    *                              the caller should set this.  Otherwise,
   221    *                              if caller sets null to this, this method will
   222    *                              compute the character to be input from
   223    *                              characters of aNativeKeyEvent.
   224    */
   225   void InitKeyEvent(NSEvent *aNativeKeyEvent, WidgetKeyboardEvent& aKeyEvent,
   226                     const nsAString *aInsertString = nullptr);
   228   /**
   229    * ComputeGeckoKeyCode() returns Gecko keycode for aNativeKeyCode on current
   230    * keyboard layout.
   231    *
   232    * @param aNativeKeyCode        A native keycode.
   233    * @param aKbType               A native Keyboard Type value.  Typically,
   234    *                              this is a result of ::LMGetKbdType().
   235    * @param aCmdIsPressed         TRUE if Cmd key is pressed.  Otherwise, FALSE.
   236    * @return                      The computed Gecko keycode.
   237    */
   238   uint32_t ComputeGeckoKeyCode(UInt32 aNativeKeyCode, UInt32 aKbType,
   239                                bool aCmdIsPressed);
   241   /**
   242    * ComputeGeckoKeyNameIndex() returns Gecko key name index for the key.
   243    *
   244    * @param aNativeKeyCode        A native keycode.
   245    */
   246   static KeyNameIndex ComputeGeckoKeyNameIndex(UInt32 aNativeKeyCode);
   248 protected:
   249   /**
   250    * TranslateToString() computes the inputted text from the native keyCode,
   251    * modifier flags and keyboard type.
   252    *
   253    * @param aKeyCode              A native keyCode.
   254    * @param aModifiers            Combination of native modifier flags.
   255    * @param aKbType               A native Keyboard Type value.  Typically,
   256    *                              this is a result of ::LMGetKbdType().
   257    * @param aStr                  Result, i.e., inputted text.
   258    *                              The result can be two or more characters.
   259    * @return                      If succeeded, TRUE.  Otherwise, FALSE.
   260    *                              Even if TRUE, aStr can be empty string.
   261    */
   262   bool TranslateToString(UInt32 aKeyCode, UInt32 aModifiers,
   263                            UInt32 aKbType, nsAString &aStr);
   265   /**
   266    * TranslateToChar() computes the inputted character from the native keyCode,
   267    * modifier flags and keyboard type.  If two or more characters would be
   268    * input, this returns 0.
   269    *
   270    * @param aKeyCode              A native keyCode.
   271    * @param aModifiers            Combination of native modifier flags.
   272    * @param aKbType               A native Keyboard Type value.  Typically,
   273    *                              this is a result of ::LMGetKbdType().
   274    * @return                      If succeeded and the result is one character,
   275    *                              returns the charCode of it.  Otherwise,
   276    *                              returns 0.
   277    */
   278   uint32_t TranslateToChar(UInt32 aKeyCode, UInt32 aModifiers, UInt32 aKbType);
   280   /**
   281    * InitKeyPressEvent() initializes aKeyEvent for aNativeKeyEvent.
   282    * Don't call this method when aKeyEvent isn't NS_KEY_PRESS.
   283    *
   284    * @param aNativeKeyEvent       A native key event for which you want to
   285    *                              dispatch a Gecko key event.
   286    * @param aInsertChar           A character to be input in an editor by the
   287    *                              event.
   288    * @param aKeyEvent             The result -- a Gecko key event initialized
   289    *                              from the native key event.  This must be
   290    *                              NS_KEY_PRESS event.
   291    * @param aKbType               A native Keyboard Type value.  Typically,
   292    *                              this is a result of ::LMGetKbdType().
   293    */
   294   void InitKeyPressEvent(NSEvent *aNativeKeyEvent,
   295                          char16_t aInsertChar,
   296                          WidgetKeyboardEvent& aKeyEvent,
   297                          UInt32 aKbType);
   299   bool GetBoolProperty(const CFStringRef aKey);
   300   bool GetStringProperty(const CFStringRef aKey, CFStringRef &aStr);
   301   bool GetStringProperty(const CFStringRef aKey, nsAString &aStr);
   303   TISInputSourceRef mInputSource;
   304   TISInputSourceRef mKeyboardLayout;
   305   CFArrayRef mInputSourceList;
   306   const UCKeyboardLayout* mUCKeyboardLayout;
   307   int8_t mIsRTL;
   309   bool mOverrideKeyboard;
   310 };
   312 /**
   313  * TextInputHandlerBase is a base class of PluginTextInputHandler,
   314  * IMEInputHandler and TextInputHandler.  Utility methods should be implemented
   315  * this level.
   316  */
   318 class TextInputHandlerBase
   319 {
   320 public:
   321   nsrefcnt AddRef()
   322   {
   323     NS_PRECONDITION(int32_t(mRefCnt) >= 0, "mRefCnt is negative");
   324     ++mRefCnt;
   325     NS_LOG_ADDREF(this, mRefCnt, "TextInputHandlerBase", sizeof(*this));
   326     return mRefCnt;
   327   }
   328   nsrefcnt Release()
   329   {
   330     NS_PRECONDITION(mRefCnt != 0, "mRefCnt is alrady zero");
   331     --mRefCnt;
   332     NS_LOG_RELEASE(this, mRefCnt, "TextInputHandlerBase");
   333     if (mRefCnt == 0) {
   334         mRefCnt = 1; /* stabilize */
   335         delete this;
   336         return 0;
   337     }
   338     return mRefCnt;
   339   }
   341   /**
   342    * DispatchEvent() dispatches aEvent on mWidget.
   343    *
   344    * @param aEvent                An event which you want to dispatch.
   345    * @return                      TRUE if the event is consumed by web contents
   346    *                              or chrome contents.  Otherwise, FALSE.
   347    */
   348   bool DispatchEvent(WidgetGUIEvent& aEvent);
   350   /**
   351    * SetSelection() dispatches NS_SELECTION_SET event for the aRange.
   352    *
   353    * @param aRange                The range which will be selected.
   354    * @return                      TRUE if setting selection is succeeded and
   355    *                              the widget hasn't been destroyed.
   356    *                              Otherwise, FALSE.
   357    */
   358   bool SetSelection(NSRange& aRange);
   360   /**
   361    * InitKeyEvent() initializes aKeyEvent for aNativeKeyEvent.
   362    *
   363    * @param aNativeKeyEvent       A native key event for which you want to
   364    *                              dispatch a Gecko key event.
   365    * @param aKeyEvent             The result -- a Gecko key event initialized
   366    *                              from the native key event.
   367    * @param aInsertString         If caller expects that the event will cause
   368    *                              a character to be input (say in an editor),
   369    *                              the caller should set this.  Otherwise,
   370    *                              if caller sets null to this, this method will
   371    *                              compute the character to be input from
   372    *                              characters of aNativeKeyEvent.
   373    */
   374   void InitKeyEvent(NSEvent *aNativeKeyEvent, WidgetKeyboardEvent& aKeyEvent,
   375                     const nsAString *aInsertString = nullptr);
   377   /**
   378    * SynthesizeNativeKeyEvent() is an implementation of
   379    * nsIWidget::SynthesizeNativeKeyEvent().  See the document in nsIWidget.h
   380    * for the detail.
   381    */
   382   nsresult SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
   383                                     int32_t aNativeKeyCode,
   384                                     uint32_t aModifierFlags,
   385                                     const nsAString& aCharacters,
   386                                     const nsAString& aUnmodifiedCharacters);
   388   /**
   389    * Utility method intended for testing. Attempts to construct a native key
   390    * event that would have been generated during an actual key press. This
   391    * *does not dispatch* the native event. Instead, it is attached to the
   392    * |mNativeKeyEvent| field of the Gecko event that is passed in.
   393    * @param aKeyEvent  Gecko key event to attach the native event to
   394    */
   395   NS_IMETHOD AttachNativeKeyEvent(WidgetKeyboardEvent& aKeyEvent);
   397   /**
   398    * GetWindowLevel() returns the window level of current focused (in Gecko)
   399    * window.  E.g., if an <input> element in XUL panel has focus, this returns
   400    * the XUL panel's window level.
   401    */
   402   NSInteger GetWindowLevel();
   404   /**
   405    * IsSpecialGeckoKey() checks whether aNativeKeyCode is mapped to a special
   406    * Gecko keyCode.  A key is "special" if it isn't used for text input.
   407    *
   408    * @param aNativeKeyCode        A native keycode.
   409    * @return                      If the keycode is mapped to a special key,
   410    *                              TRUE.  Otherwise, FALSE.
   411    */
   412   static bool IsSpecialGeckoKey(UInt32 aNativeKeyCode);
   415   /**
   416    * EnableSecureEventInput() and DisableSecureEventInput() wrap the Carbon
   417    * Event Manager APIs with the same names.  In addition they keep track of
   418    * how many times we've called them (in the same process) -- unlike the
   419    * Carbon Event Manager APIs, which only keep track of how many times they've
   420    * been called from any and all processes.
   421    *
   422    * The Carbon Event Manager's IsSecureEventInputEnabled() returns whether
   423    * secure event input mode is enabled (in any process).  This class's
   424    * IsSecureEventInputEnabled() returns whether we've made any calls to
   425    * EnableSecureEventInput() that are not (yet) offset by the calls we've
   426    * made to DisableSecureEventInput().
   427    */
   428   static void EnableSecureEventInput();
   429   static void DisableSecureEventInput();
   430   static bool IsSecureEventInputEnabled();
   432   /**
   433    * EnsureSecureEventInputDisabled() calls DisableSecureEventInput() until
   434    * our call count becomes 0.
   435    */
   436   static void EnsureSecureEventInputDisabled();
   438 protected:
   439   nsAutoRefCnt mRefCnt;
   441 public:
   442    /**
   443    * mWidget must not be destroyed without OnDestroyWidget being called.
   444    *
   445    * @param aDestroyingWidget     Destroying widget.  This might not be mWidget.
   446    * @return                      This result doesn't have any meaning for
   447    *                              callers.  When aDstroyingWidget isn't the same
   448    *                              as mWidget, FALSE.  Then, inherited methods in
   449    *                              sub classes should return from this method
   450    *                              without cleaning up.
   451    */
   452   virtual bool OnDestroyWidget(nsChildView* aDestroyingWidget);
   454 protected:
   455   // The creater of this instance and client.
   456   // This must not be null after initialized until OnDestroyWidget() is called.
   457   nsChildView* mWidget; // [WEAK]
   459   // The native view for mWidget.
   460   // This view handles the actual text inputting.
   461   NSView<mozView>* mView; // [STRONG]
   463   TextInputHandlerBase(nsChildView* aWidget, NSView<mozView> *aNativeView);
   464   virtual ~TextInputHandlerBase();
   466   bool Destroyed() { return !mWidget; }
   468   /**
   469    * mCurrentKeyEvent indicates what key event we are handling.  While
   470    * handling a native keydown event, we need to store the event for insertText,
   471    * doCommandBySelector and various action message handlers of NSResponder
   472    * such as [NSResponder insertNewline:sender].
   473    */
   474   struct KeyEventState
   475   {
   476     // Handling native key event
   477     NSEvent* mKeyEvent;
   478     // Whether keydown event was consumed by web contents or chrome contents.
   479     bool mKeyDownHandled;
   480     // Whether keypress event was dispatched for mKeyEvent.
   481     bool mKeyPressDispatched;
   482     // Whether keypress event was consumed by web contents or chrome contents.
   483     bool mKeyPressHandled;
   484     // Whether the key event causes other key events via IME or something.
   485     bool mCausedOtherKeyEvents;
   487     KeyEventState() : mKeyEvent(nullptr)
   488     {
   489       Clear();
   490     }    
   492     KeyEventState(NSEvent* aNativeKeyEvent) : mKeyEvent(nullptr)
   493     {
   494       Clear();
   495       Set(aNativeKeyEvent);
   496     }
   498     KeyEventState(const KeyEventState &aOther) : mKeyEvent(nullptr)
   499     {
   500       Clear();
   501       if (aOther.mKeyEvent) {
   502         mKeyEvent = [aOther.mKeyEvent retain];
   503       }
   504       mKeyDownHandled = aOther.mKeyDownHandled;
   505       mKeyPressDispatched = aOther.mKeyPressDispatched;
   506       mKeyPressHandled = aOther.mKeyPressHandled;
   507       mCausedOtherKeyEvents = aOther.mCausedOtherKeyEvents;
   508     }
   510     ~KeyEventState()
   511     {
   512       Clear();
   513     }
   515     void Set(NSEvent* aNativeKeyEvent)
   516     {
   517       NS_PRECONDITION(aNativeKeyEvent, "aNativeKeyEvent must not be NULL");
   518       Clear();
   519       mKeyEvent = [aNativeKeyEvent retain];
   520     }
   522     void Clear()
   523     {
   524       if (mKeyEvent) {
   525         [mKeyEvent release];
   526         mKeyEvent = nullptr;
   527       }
   528       mKeyDownHandled = false;
   529       mKeyPressDispatched = false;
   530       mKeyPressHandled = false;
   531       mCausedOtherKeyEvents = false;
   532     }
   534     bool IsDefaultPrevented() const
   535     {
   536       return mKeyDownHandled || mKeyPressHandled || mCausedOtherKeyEvents;
   537     }
   539     bool CanDispatchKeyPressEvent() const
   540     {
   541       return !mKeyPressDispatched && !IsDefaultPrevented();
   542     }
   543   };
   545   /**
   546    * Helper class for guaranteeing cleaning mCurrentKeyEvent
   547    */
   548   class AutoKeyEventStateCleaner
   549   {
   550   public:
   551     AutoKeyEventStateCleaner(TextInputHandlerBase* aHandler) :
   552       mHandler(aHandler)
   553     {
   554     }
   556     ~AutoKeyEventStateCleaner()
   557     {
   558       mHandler->RemoveCurrentKeyEvent();
   559     }
   560   private:
   561     nsRefPtr<TextInputHandlerBase> mHandler;
   562   };
   564   /**
   565    * mCurrentKeyEvents stores all key events which are being processed.
   566    * When we call interpretKeyEvents, IME may generate other key events.
   567    * mCurrentKeyEvents[0] is the latest key event.
   568    */
   569   nsTArray<KeyEventState*> mCurrentKeyEvents;
   571   /**
   572    * mFirstKeyEvent must be used for first key event.  This member prevents
   573    * memory fragmentation for most key events.
   574    */
   575   KeyEventState mFirstKeyEvent;
   577   /**
   578    * PushKeyEvent() adds the current key event to mCurrentKeyEvents.
   579    */
   580   KeyEventState* PushKeyEvent(NSEvent* aNativeKeyEvent)
   581   {
   582     uint32_t nestCount = mCurrentKeyEvents.Length();
   583     for (uint32_t i = 0; i < nestCount; i++) {
   584       // When the key event is caused by another key event, all key events
   585       // which are being handled should be marked as "consumed".
   586       mCurrentKeyEvents[i]->mCausedOtherKeyEvents = true;
   587     }
   589     KeyEventState* keyEvent = nullptr;
   590     if (nestCount == 0) {
   591       mFirstKeyEvent.Set(aNativeKeyEvent);
   592       keyEvent = &mFirstKeyEvent;
   593     } else {
   594       keyEvent = new KeyEventState(aNativeKeyEvent);
   595     }
   596     return *mCurrentKeyEvents.AppendElement(keyEvent);
   597   }
   599   /**
   600    * RemoveCurrentKeyEvent() removes the current key event from
   601    * mCurrentKeyEvents.
   602    */
   603   void RemoveCurrentKeyEvent()
   604   {
   605     NS_ASSERTION(mCurrentKeyEvents.Length() > 0,
   606                  "RemoveCurrentKeyEvent() is called unexpectedly");
   607     KeyEventState* keyEvent = GetCurrentKeyEvent();
   608     mCurrentKeyEvents.RemoveElementAt(mCurrentKeyEvents.Length() - 1);
   609     if (keyEvent == &mFirstKeyEvent) {
   610       keyEvent->Clear();
   611     } else {
   612       delete keyEvent;
   613     }
   614   }
   616   /**
   617    * GetCurrentKeyEvent() returns current processing key event.
   618    */
   619   KeyEventState* GetCurrentKeyEvent()
   620   {
   621     if (mCurrentKeyEvents.Length() == 0) {
   622       return nullptr;
   623     }
   624     return mCurrentKeyEvents[mCurrentKeyEvents.Length() - 1];
   625   }
   627   /**
   628    * IsPrintableChar() checks whether the unicode character is
   629    * a non-printable ASCII character or not.  Note that this returns
   630    * TRUE even if aChar is a non-printable UNICODE character.
   631    *
   632    * @param aChar                 A unicode character.
   633    * @return                      TRUE if aChar is a printable ASCII character
   634    *                              or a unicode character.  Otherwise, i.e,
   635    *                              if aChar is a non-printable ASCII character,
   636    *                              FALSE.
   637    */
   638   static bool IsPrintableChar(char16_t aChar);
   640   /**
   641    * IsNormalCharInputtingEvent() checks whether aKeyEvent causes text input.
   642    *
   643    * @param aKeyEvent             A key event.
   644    * @return                      TRUE if the key event causes text input.
   645    *                              Otherwise, FALSE.
   646    */
   647   static bool IsNormalCharInputtingEvent(const WidgetKeyboardEvent& aKeyEvent);
   649   /**
   650    * IsModifierKey() checks whether the native keyCode is for a modifier key.
   651    *
   652    * @param aNativeKeyCode        A native keyCode.
   653    * @return                      TRUE if aNativeKeyCode is for a modifier key.
   654    *                              Otherwise, FALSE.
   655    */
   656   static bool IsModifierKey(UInt32 aNativeKeyCode);
   658 private:
   659   struct KeyboardLayoutOverride {
   660     int32_t mKeyboardLayout;
   661     bool mOverrideEnabled;
   663     KeyboardLayoutOverride() :
   664       mKeyboardLayout(0), mOverrideEnabled(false)
   665     {
   666     }
   667   };
   669   KeyboardLayoutOverride mKeyboardOverride;
   671   static int32_t sSecureEventInputCount;
   672 };
   674 /**
   675  * PluginTextInputHandler handles text input events for plugins.
   676  */
   678 class PluginTextInputHandler : public TextInputHandlerBase
   679 {
   680 public:
   682   /**
   683    * When starting complex text input for current event on plugin, this is
   684    * called.  See also the comment of StartComplexTextInputForCurrentEvent() of
   685    * nsIPluginWidget.
   686    */
   687   nsresult StartComplexTextInputForCurrentEvent()
   688   {
   689     mPluginComplexTextInputRequested = true;
   690     return NS_OK;
   691   }
   693   /**
   694    * HandleKeyDownEventForPlugin() handles aNativeKeyEvent.
   695    *
   696    * @param aNativeKeyEvent       A native NSKeyDown event.
   697    */
   698   void HandleKeyDownEventForPlugin(NSEvent* aNativeKeyEvent);
   700   /**
   701    * HandleKeyUpEventForPlugin() handles aNativeKeyEvent.
   702    *
   703    * @param aNativeKeyEvent       A native NSKeyUp event.
   704    */
   705   void HandleKeyUpEventForPlugin(NSEvent* aNativeKeyEvent);
   707   /**
   708    * ConvertCocoaKeyEventToNPCocoaEvent() converts aCocoaEvent to NPCocoaEvent.
   709    *
   710    * @param aCocoaEvent           A native key event.
   711    * @param aPluginEvent          The result.
   712    */
   713   static void ConvertCocoaKeyEventToNPCocoaEvent(NSEvent* aCocoaEvent,
   714                                                  NPCocoaEvent& aPluginEvent);
   716 #ifndef __LP64__
   718   /**
   719    * InstallPluginKeyEventsHandler() is called when initializing process.
   720    * RemovePluginKeyEventsHandler() is called when finalizing process.
   721    * These methods initialize/finalize global resource for handling events for
   722    * plugins.
   723    */
   724   static void InstallPluginKeyEventsHandler();
   725   static void RemovePluginKeyEventsHandler();
   727   /**
   728    * This must be called before first key/IME event for plugins.
   729    * This method initializes IMKInputSession methods swizzling.
   730    */
   731   static void SwizzleMethods();
   733   /**
   734    * When a composition starts or finishes, this is called.
   735    */
   736   void SetPluginTSMInComposition(bool aInComposition)
   737   {
   738     mPluginTSMInComposition = aInComposition;
   739   }
   741 #endif // #ifndef __LP64__
   743 protected:
   744   bool mIgnoreNextKeyUpEvent;
   746   PluginTextInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView);
   747   ~PluginTextInputHandler();
   749 private:
   751 #ifndef __LP64__
   752   TSMDocumentID mPluginTSMDoc;
   754   bool mPluginTSMInComposition;
   755 #endif // #ifndef __LP64__
   757   bool mPluginComplexTextInputRequested;
   759   /**
   760    * DispatchCocoaNPAPITextEvent() dispatches a text event for Cocoa plugin.
   761    *
   762    * @param aString               A string inputted by the dispatching event.
   763    * @return                      TRUE if the dispatched event was consumed.
   764    *                              Otherwise, FALSE.
   765    */
   766   bool DispatchCocoaNPAPITextEvent(NSString* aString);
   768   /**
   769    * Whether the plugin is in composition or not.
   770    * On 32bit build, this returns the state of mPluginTSMInComposition.
   771    * On 64bit build, this returns ComplexTextInputPanel's state.
   772    *
   773    * @return                      TRUE if plugin is in composition.  Otherwise,
   774    *                              FALSE.
   775    */
   776   bool IsInPluginComposition();
   778 #ifndef __LP64__
   780   /**
   781    * Create a TSM document for use with plugins, so that we can support IME in
   782    * them.  Once it's created, if need be (re)activate it.  Some plugins (e.g.
   783    * the Flash plugin running in Camino) don't create their own TSM document --
   784    * without which IME can't work.  Others (e.g. the Flash plugin running in
   785    * Firefox) create a TSM document that (somehow) makes the input window behave
   786    * badly when it contains more than one kind of input (say Hiragana and
   787    * Romaji).  (We can't just use the per-NSView TSM documents that Cocoa
   788    * provides (those created and managed by the NSTSMInputContext class) -- for
   789    * some reason TSMProcessRawKeyEvent() doesn't work with them.)
   790    */
   791   void ActivatePluginTSMDocument();
   793   /**
   794    * HandleCarbonPluginKeyEvent() handles the aKeyEvent.  This is called by
   795    * PluginKeyEventsHandler().
   796    *
   797    * @param aKeyEvent             A native Carbon event.
   798    */
   799   void HandleCarbonPluginKeyEvent(EventRef aKeyEvent);
   801   /**
   802    * Target for text services events sent as the result of calls made to
   803    * TSMProcessRawKeyEvent() in HandleKeyDownEventForPlugin() when a plugin has
   804    * the focus.  The calls to TSMProcessRawKeyEvent() short-circuit Cocoa-based
   805    * IME (which would otherwise interfere with our efforts) and allow Carbon-
   806    * based IME to work in plugins (via the NPAPI).  This strategy doesn't cause
   807    * trouble for plugins that (like the Java Embedding Plugin) bypass the NPAPI
   808    * to get their keyboard events and do their own Cocoa-based IME.
   809    */
   810   static OSStatus PluginKeyEventsHandler(EventHandlerCallRef aHandlerRef,
   811                                          EventRef aEvent,
   812                                          void *aUserData);
   814   static EventHandlerRef sPluginKeyEventsHandler;
   816 #endif // #ifndef __LP64__
   817 };
   819 /**
   820  * IMEInputHandler manages:
   821  *   1. The IME/keyboard layout statement of nsChildView.
   822  *   2. The IME composition statement of nsChildView.
   823  * And also provides the methods which controls the current IME transaction of
   824  * the instance.
   825  *
   826  * Note that an nsChildView handles one or more NSView's events.  E.g., even if
   827  * a text editor on XUL panel element, the input events handled on the parent
   828  * (or its ancestor) widget handles it (the native focus is set to it).  The
   829  * actual focused view is notified by OnFocusChangeInGecko.
   830  */
   832 class IMEInputHandler : public PluginTextInputHandler
   833 {
   834 public:
   835   virtual bool OnDestroyWidget(nsChildView* aDestroyingWidget);
   837   virtual void OnFocusChangeInGecko(bool aFocus);
   839   void OnSelectionChange() { mSelectedRange.location = NSNotFound; }
   841   /**
   842    * DispatchTextEvent() dispatches a text event on mWidget.
   843    *
   844    * @param aText                 User text input.
   845    * @param aAttrString           An NSAttributedString instance which indicates
   846    *                              current composition string.
   847    * @param aSelectedRange        Current selected range (or caret position).
   848    * @param aDoCommit             TRUE if the composition string should be
   849    *                              committed.  Otherwise, FALSE.
   850    */
   851   bool DispatchTextEvent(const nsString& aText,
   852                            NSAttributedString* aAttrString,
   853                            NSRange& aSelectedRange,
   854                            bool aDoCommit);
   856   /**
   857    * SetMarkedText() is a handler of setMarkedText of NSTextInput.
   858    *
   859    * @param aAttrString           This mut be an instance of NSAttributedString.
   860    *                              If the aString parameter to
   861    *                              [ChildView setMarkedText:setSelectedRange:]
   862    *                              isn't an instance of NSAttributedString,
   863    *                              create an NSAttributedString from it and pass
   864    *                              that instead.
   865    * @param aSelectedRange        Current selected range (or caret position).
   866    * @param aReplacementRange     The range which will be replaced with the
   867    *                              aAttrString instead of current marked range.
   868    */
   869   void SetMarkedText(NSAttributedString* aAttrString,
   870                      NSRange& aSelectedRange,
   871                      NSRange* aReplacementRange = nullptr);
   873   /**
   874    * ConversationIdentifier() returns an ID for the current editor.  The ID is
   875    * guaranteed to be unique among currently existing editors.  But it might be
   876    * the same as the ID of an editor that has already been destroyed.
   877    *
   878    * @return                      An identifier of current focused editor.
   879    */
   880   NSInteger ConversationIdentifier();
   882   /**
   883    * GetAttributedSubstringFromRange() returns an NSAttributedString instance
   884    * which is allocated as autorelease for aRange.
   885    *
   886    * @param aRange                The range of string which you want.
   887    * @param aActualRange          The actual range of the result.
   888    * @return                      The string in aRange.  If the string is empty,
   889    *                              this returns nil.  If succeeded, this returns
   890    *                              an instance which is allocated as autorelease.
   891    *                              If this has some troubles, returns nil.
   892    */
   893   NSAttributedString* GetAttributedSubstringFromRange(
   894                         NSRange& aRange,
   895                         NSRange* aActualRange = nullptr);
   897   /**
   898    * SelectedRange() returns current selected range.
   899    *
   900    * @return                      If an editor has focus, this returns selection
   901    *                              range in the editor.  Otherwise, this returns
   902    *                              selection range  in the focused document.
   903    */
   904   NSRange SelectedRange();
   906   /**
   907    * FirstRectForCharacterRange() returns first *character* rect in the range.
   908    * Cocoa needs the first line rect in the range, but we cannot compute it
   909    * on current implementation.
   910    *
   911    * @param aRange                A range of text to examine.  Its position is
   912    *                              an offset from the beginning of the focused
   913    *                              editor or document.
   914    * @param aActualRange          If this is not null, this returns the actual
   915    *                              range used for computing the result.
   916    * @return                      An NSRect containing the first character in
   917    *                              aRange, in screen coordinates.
   918    *                              If the length of aRange is 0, the width will
   919    *                              be 0.
   920    */
   921   NSRect FirstRectForCharacterRange(NSRange& aRange,
   922                                     NSRange* aActualRange = nullptr);
   924   /**
   925    * CharacterIndexForPoint() returns an offset of a character at aPoint.
   926    * XXX This isn't implemented, always returns 0.
   927    *
   928    * @param                       The point in screen coordinates.
   929    * @return                      The offset of the character at aPoint from
   930    *                              the beginning of the focused editor or
   931    *                              document.
   932    */
   933   NSUInteger CharacterIndexForPoint(NSPoint& aPoint);
   935   /**
   936    * GetValidAttributesForMarkedText() returns attributes which we support.
   937    *
   938    * @return                      Always empty array for now.
   939    */
   940   NSArray* GetValidAttributesForMarkedText();
   942   bool HasMarkedText();
   943   NSRange MarkedRange();
   945   bool IsIMEComposing() { return mIsIMEComposing; }
   946   bool IsIMEOpened();
   947   bool IsIMEEnabled() { return mIsIMEEnabled; }
   948   bool IsASCIICapableOnly() { return mIsASCIICapableOnly; }
   949   bool IgnoreIMECommit() { return mIgnoreIMECommit; }
   951   bool IgnoreIMEComposition()
   952   {
   953     // Ignore the IME composition events when we're pending to discard the
   954     // composition and we are not to handle the IME composition now.
   955     return (mPendingMethods & kDiscardIMEComposition) &&
   956            (mIsInFocusProcessing || !IsFocused());
   957   }
   959   void CommitIMEComposition();
   960   void CancelIMEComposition();
   962   void EnableIME(bool aEnableIME);
   963   void SetIMEOpenState(bool aOpen);
   964   void SetASCIICapableOnly(bool aASCIICapableOnly);
   966   bool IsFocused();
   968   static CFArrayRef CreateAllIMEModeList();
   969   static void DebugPrintAllIMEModes();
   971   // Don't use ::TSMGetActiveDocument() API directly, the document may not
   972   // be what you want.
   973   static TSMDocumentID GetCurrentTSMDocumentID();
   975 protected:
   976   // We cannot do some jobs in the given stack by some reasons.
   977   // Following flags and the timer provide the execution pending mechanism,
   978   // See the comment in nsCocoaTextInputHandler.mm.
   979   nsCOMPtr<nsITimer> mTimer;
   980   enum {
   981     kNotifyIMEOfFocusChangeInGecko = 1,
   982     kDiscardIMEComposition         = 2,
   983     kSyncASCIICapableOnly          = 4
   984   };
   985   uint32_t mPendingMethods;
   987   IMEInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView);
   988   virtual ~IMEInputHandler();
   990   void ResetTimer();
   992   virtual void ExecutePendingMethods();
   994   /**
   995    * InsertTextAsCommittingComposition() commits current composition.  If there
   996    * is no composition, this starts a composition and commits it immediately.
   997    *
   998    * @param aAttrString           A string which is committed.
   999    * @param aReplacementRange     The range which will be replaced with the
  1000    *                              aAttrString instead of current selection.
  1001    */
  1002   void InsertTextAsCommittingComposition(NSAttributedString* aAttrString,
  1003                                          NSRange* aReplacementRange);
  1005 private:
  1006   // If mIsIMEComposing is true, the composition string is stored here.
  1007   NSString* mIMECompositionString;
  1008   // mLastDispatchedCompositionString stores the lastest dispatched composition
  1009   // string by compositionupdate event.
  1010   nsString mLastDispatchedCompositionString;
  1012   NSRange mMarkedRange;
  1013   NSRange mSelectedRange;
  1015   bool mIsIMEComposing;
  1016   bool mIsIMEEnabled;
  1017   bool mIsASCIICapableOnly;
  1018   bool mIgnoreIMECommit;
  1019   // This flag is enabled by OnFocusChangeInGecko, and will be cleared by
  1020   // ExecutePendingMethods.  When this is true, IsFocus() returns TRUE.  At
  1021   // that time, the focus processing in Gecko might not be finished yet.  So,
  1022   // you cannot use WidgetQueryContentEvent or something.
  1023   bool mIsInFocusProcessing;
  1024   bool mIMEHasFocus;
  1026   void KillIMEComposition();
  1027   void SendCommittedText(NSString *aString);
  1028   void OpenSystemPreferredLanguageIME();
  1030   // Pending methods
  1031   void NotifyIMEOfFocusChangeInGecko();
  1032   void DiscardIMEComposition();
  1033   void SyncASCIICapableOnly();
  1035   static bool sStaticMembersInitialized;
  1036   static CFStringRef sLatestIMEOpenedModeInputSourceID;
  1037   static void InitStaticMembers();
  1038   static void OnCurrentTextInputSourceChange(CFNotificationCenterRef aCenter,
  1039                                              void* aObserver,
  1040                                              CFStringRef aName,
  1041                                              const void* aObject,
  1042                                              CFDictionaryRef aUserInfo);
  1044   static void FlushPendingMethods(nsITimer* aTimer, void* aClosure);
  1046   /**
  1047    * ConvertToTextRangeStyle converts the given native underline style to
  1048    * our defined text range type.
  1050    * @param aUnderlineStyle       NSUnderlineStyleSingle or
  1051    *                              NSUnderlineStyleThick.
  1052    * @param aSelectedRange        Current selected range (or caret position).
  1053    * @return                      NS_TEXTRANGE_*.
  1054    */
  1055   uint32_t ConvertToTextRangeType(uint32_t aUnderlineStyle,
  1056                                   NSRange& aSelectedRange);
  1058   /**
  1059    * GetRangeCount() computes the range count of aAttrString.
  1061    * @param aAttrString           An NSAttributedString instance whose number of
  1062    *                              NSUnderlineStyleAttributeName ranges you with
  1063    *                              to know.
  1064    * @return                      The count of NSUnderlineStyleAttributeName
  1065    *                              ranges in aAttrString.
  1066    */
  1067   uint32_t GetRangeCount(NSAttributedString *aString);
  1069   /**
  1070    * CreateTextRangeArray() returns text ranges for clauses and/or caret.
  1072    * @param aAttrString           An NSAttributedString instance which indicates
  1073    *                              current composition string.
  1074    * @param aSelectedRange        Current selected range (or caret position).
  1075    * @return                      The result is set to the
  1076    *                              NSUnderlineStyleAttributeName ranges in
  1077    *                              aAttrString.
  1078    */
  1079   already_AddRefed<mozilla::TextRangeArray>
  1080     CreateTextRangeArray(NSAttributedString *aAttrString,
  1081                          NSRange& aSelectedRange);
  1083   /**
  1084    * InitCompositionEvent() initializes aCompositionEvent.
  1086    * @param aCompositionEvent     A composition event which you want to
  1087    *                              initialize.
  1088    */
  1089   void InitCompositionEvent(WidgetCompositionEvent& aCompositionEvent);
  1091   /**
  1092    * When a composition starts, OnStartIMEComposition() is called.
  1093    */
  1094   void OnStartIMEComposition();
  1096   /**
  1097    * When a composition is updated, OnUpdateIMEComposition() is called.
  1098    */
  1099   void OnUpdateIMEComposition(NSString* aIMECompositionString);
  1101   /**
  1102    * When a composition is finished, OnEndIMEComposition() is called.
  1103    */
  1104   void OnEndIMEComposition();
  1106   // The focused IME handler.  Please note that the handler might lost the
  1107   // actual focus by deactivating the application.  If we are active, this
  1108   // must have the actual focused handle.
  1109   // We cannot access to the NSInputManager during we aren't active, so, the
  1110   // focused handler can have an IME transaction even if we are deactive.
  1111   static IMEInputHandler* sFocusedIMEHandler;
  1112 };
  1114 /**
  1115  * TextInputHandler implements the NSTextInput protocol.
  1116  */
  1117 class TextInputHandler : public IMEInputHandler
  1119 public:
  1120   static NSUInteger sLastModifierState;
  1122   static CFArrayRef CreateAllKeyboardLayoutList();
  1123   static void DebugPrintAllKeyboardLayouts();
  1125   TextInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView);
  1126   virtual ~TextInputHandler();
  1128   /**
  1129    * KeyDown event handler.
  1131    * @param aNativeEvent          A native NSKeyDown event.
  1132    * @return                      TRUE if the event is consumed by web contents
  1133    *                              or chrome contents.  Otherwise, FALSE.
  1134    */
  1135   bool HandleKeyDownEvent(NSEvent* aNativeEvent);
  1137   /**
  1138    * KeyUp event handler.
  1140    * @param aNativeEvent          A native NSKeyUp event.
  1141    */
  1142   void HandleKeyUpEvent(NSEvent* aNativeEvent);
  1144   /**
  1145    * FlagsChanged event handler.
  1147    * @param aNativeEvent          A native NSFlagsChanged event.
  1148    */
  1149   void HandleFlagsChanged(NSEvent* aNativeEvent);
  1151   /**
  1152    * Insert the string to content.  I.e., this is a text input event handler.
  1153    * If this is called during keydown event handling, this may dispatch a
  1154    * NS_KEY_PRESS event.  If this is called during composition, this commits
  1155    * the composition by the aAttrString.
  1157    * @param aAttrString           An inserted string.
  1158    * @param aReplacementRange     The range which will be replaced with the
  1159    *                              aAttrString instead of current selection.
  1160    */
  1161   void InsertText(NSAttributedString *aAttrString,
  1162                   NSRange* aReplacementRange = nullptr);
  1164   /**
  1165    * doCommandBySelector event handler.
  1167    * @param aSelector             A selector of the command.
  1168    * @return                      TRUE if the command is consumed.  Otherwise,
  1169    *                              FALSE.
  1170    */
  1171   bool DoCommandBySelector(const char* aSelector);
  1173   /**
  1174    * KeyPressWasHandled() checks whether keypress event was handled or not.
  1176    * @return                      TRUE if keypress event for latest native key
  1177    *                              event was handled.  Otherwise, FALSE.
  1178    *                              If this handler isn't handling any key events,
  1179    *                              always returns FALSE.
  1180    */
  1181   bool KeyPressWasHandled()
  1183     KeyEventState* currentKeyEvent = GetCurrentKeyEvent();
  1184     return currentKeyEvent && currentKeyEvent->mKeyPressHandled;
  1187 protected:
  1188   // Stores the association of device dependent modifier flags with a modifier
  1189   // keyCode.  Being device dependent, this association may differ from one kind
  1190   // of hardware to the next.
  1191   struct ModifierKey
  1193     NSUInteger flags;
  1194     unsigned short keyCode;
  1196     ModifierKey(NSUInteger aFlags, unsigned short aKeyCode) :
  1197       flags(aFlags), keyCode(aKeyCode)
  1201     NSUInteger GetDeviceDependentFlags() const
  1203       return (flags & ~NSDeviceIndependentModifierFlagsMask);
  1206     NSUInteger GetDeviceIndependentFlags() const
  1208       return (flags & NSDeviceIndependentModifierFlagsMask);
  1210   };
  1211   typedef nsTArray<ModifierKey> ModifierKeyArray;
  1212   ModifierKeyArray mModifierKeys;
  1214   /**
  1215    * GetModifierKeyForNativeKeyCode() returns the stored ModifierKey for
  1216    * the key.
  1217    */
  1218   const ModifierKey*
  1219     GetModifierKeyForNativeKeyCode(unsigned short aKeyCode) const;
  1221   /**
  1222    * GetModifierKeyForDeviceDependentFlags() returns the stored ModifierKey for
  1223    * the device dependent flags.
  1224    */
  1225   const ModifierKey*
  1226     GetModifierKeyForDeviceDependentFlags(NSUInteger aFlags) const;
  1228   /**
  1229    * DispatchKeyEventForFlagsChanged() dispatches keydown event or keyup event
  1230    * for the aNativeEvent.
  1232    * @param aNativeEvent          A native flagschanged event which you want to
  1233    *                              dispatch our key event for.
  1234    * @param aDispatchKeyDown      TRUE if you want to dispatch a keydown event.
  1235    *                              Otherwise, i.e., to dispatch keyup event,
  1236    *                              FALSE.
  1237    */
  1238   void DispatchKeyEventForFlagsChanged(NSEvent* aNativeEvent,
  1239                                        bool aDispatchKeyDown);
  1240 };
  1242 } // namespace widget
  1243 } // namespace mozilla
  1245 #endif // TextInputHandler_h_

mercurial