widget/cocoa/TextInputHandler.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/widget/cocoa/TextInputHandler.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1245 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 sw=2 et tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef TextInputHandler_h_
    1.11 +#define TextInputHandler_h_
    1.12 +
    1.13 +#include "nsCocoaUtils.h"
    1.14 +
    1.15 +#import <Carbon/Carbon.h>
    1.16 +#import <Cocoa/Cocoa.h>
    1.17 +#include "mozView.h"
    1.18 +#include "nsString.h"
    1.19 +#include "nsCOMPtr.h"
    1.20 +#include "nsITimer.h"
    1.21 +#include "npapi.h"
    1.22 +#include "nsTArray.h"
    1.23 +#include "mozilla/EventForwards.h"
    1.24 +
    1.25 +class nsChildView;
    1.26 +
    1.27 +namespace mozilla {
    1.28 +namespace widget {
    1.29 +
    1.30 +// Key code constants
    1.31 +enum
    1.32 +{
    1.33 +  kVK_RightCommand    = 0x36, // right command key
    1.34 +
    1.35 +  kVK_PC_PrintScreen     = kVK_F13,
    1.36 +  kVK_PC_ScrollLock      = kVK_F14,
    1.37 +  kVK_PC_Pause           = kVK_F15,
    1.38 +
    1.39 +  kVK_PC_Insert          = kVK_Help,
    1.40 +  kVK_PC_Backspace       = kVK_Delete,
    1.41 +  kVK_PC_Delete          = kVK_ForwardDelete,
    1.42 +
    1.43 +  kVK_PC_ContextMenu     = 0x6E,
    1.44 +
    1.45 +  kVK_Powerbook_KeypadEnter = 0x34  // Enter on Powerbook's keyboard is different
    1.46 +};
    1.47 +
    1.48 +/**
    1.49 + * TISInputSourceWrapper is a wrapper for the TISInputSourceRef.  If we get the
    1.50 + * TISInputSourceRef from InputSourceID, we need to release the CFArray instance
    1.51 + * which is returned by TISCreateInputSourceList.  However, when we release the
    1.52 + * list, we cannot access the TISInputSourceRef.  So, it's not usable, and it
    1.53 + * may cause the memory leak bugs.  nsTISInputSource automatically releases the
    1.54 + * list when the instance is destroyed.
    1.55 + */
    1.56 +class TISInputSourceWrapper
    1.57 +{
    1.58 +public:
    1.59 +  static TISInputSourceWrapper& CurrentInputSource();
    1.60 +
    1.61 +  TISInputSourceWrapper()
    1.62 +  {
    1.63 +    mInputSourceList = nullptr;
    1.64 +    Clear();
    1.65 +  }
    1.66 +
    1.67 +  TISInputSourceWrapper(const char* aID)
    1.68 +  {
    1.69 +    mInputSourceList = nullptr;
    1.70 +    InitByInputSourceID(aID);
    1.71 +  }
    1.72 +
    1.73 +  TISInputSourceWrapper(SInt32 aLayoutID)
    1.74 +  {
    1.75 +    mInputSourceList = nullptr;
    1.76 +    InitByLayoutID(aLayoutID);
    1.77 +  }
    1.78 +
    1.79 +  TISInputSourceWrapper(TISInputSourceRef aInputSource)
    1.80 +  {
    1.81 +    mInputSourceList = nullptr;
    1.82 +    InitByTISInputSourceRef(aInputSource);
    1.83 +  }
    1.84 +
    1.85 +  ~TISInputSourceWrapper() { Clear(); }
    1.86 +
    1.87 +  void InitByInputSourceID(const char* aID);
    1.88 +  void InitByInputSourceID(const nsAFlatString &aID);
    1.89 +  void InitByInputSourceID(const CFStringRef aID);
    1.90 +  /**
    1.91 +   * InitByLayoutID() initializes the keyboard layout by the layout ID.
    1.92 +   *
    1.93 +   * @param aLayoutID             An ID of keyboard layout.
    1.94 +   *                                0: US
    1.95 +   *                                1: Greek
    1.96 +   *                                2: German
    1.97 +   *                                3: Swedish-Pro
    1.98 +   *                                4: Dvorak-Qwerty Cmd
    1.99 +   *                                5: Thai
   1.100 +   *                                6: Arabic
   1.101 +   *                                7: French
   1.102 +   *                                8: Hebrew
   1.103 +   *                                9: Lithuanian
   1.104 +   *                               10: Norwegian
   1.105 +   *                               11: Spanish
   1.106 +   * @param aOverrideKeyboard     When testing set to TRUE, otherwise, set to
   1.107 +   *                              FALSE.  When TRUE, we use an ANSI keyboard
   1.108 +   *                              instead of the actual keyboard.
   1.109 +   */
   1.110 +  void InitByLayoutID(SInt32 aLayoutID, bool aOverrideKeyboard = false);
   1.111 +  void InitByCurrentInputSource();
   1.112 +  void InitByCurrentKeyboardLayout();
   1.113 +  void InitByCurrentASCIICapableInputSource();
   1.114 +  void InitByCurrentASCIICapableKeyboardLayout();
   1.115 +  void InitByCurrentInputMethodKeyboardLayoutOverride();
   1.116 +  void InitByTISInputSourceRef(TISInputSourceRef aInputSource);
   1.117 +  void InitByLanguage(CFStringRef aLanguage);
   1.118 +
   1.119 +  /**
   1.120 +   * If the instance is initialized with a keyboard layout input source,
   1.121 +   * returns it.
   1.122 +   * If the instance is initialized with an IME mode input source, the result
   1.123 +   * references the keyboard layout for the IME mode.  However, this can be
   1.124 +   * initialized only when the IME mode is actually selected.  I.e, if IME mode
   1.125 +   * input source is initialized with LayoutID or SourceID, this returns null.
   1.126 +   */
   1.127 +  TISInputSourceRef GetKeyboardLayoutInputSource() const
   1.128 +  {
   1.129 +    return mKeyboardLayout;
   1.130 +  }
   1.131 +  const UCKeyboardLayout* GetUCKeyboardLayout();
   1.132 +
   1.133 +  bool IsOpenedIMEMode();
   1.134 +  bool IsIMEMode();
   1.135 +  bool IsKeyboardLayout();
   1.136 +
   1.137 +  bool IsASCIICapable()
   1.138 +  {
   1.139 +    NS_ENSURE_TRUE(mInputSource, false);
   1.140 +    return GetBoolProperty(kTISPropertyInputSourceIsASCIICapable);
   1.141 +  }
   1.142 +
   1.143 +  bool IsEnabled()
   1.144 +  {
   1.145 +    NS_ENSURE_TRUE(mInputSource, false);
   1.146 +    return GetBoolProperty(kTISPropertyInputSourceIsEnabled);
   1.147 +  }
   1.148 +
   1.149 +  bool GetLanguageList(CFArrayRef &aLanguageList);
   1.150 +  bool GetPrimaryLanguage(CFStringRef &aPrimaryLanguage);
   1.151 +  bool GetPrimaryLanguage(nsAString &aPrimaryLanguage);
   1.152 +
   1.153 +  bool GetLocalizedName(CFStringRef &aName)
   1.154 +  {
   1.155 +    NS_ENSURE_TRUE(mInputSource, false);
   1.156 +    return GetStringProperty(kTISPropertyLocalizedName, aName);
   1.157 +  }
   1.158 +
   1.159 +  bool GetLocalizedName(nsAString &aName)
   1.160 +  {
   1.161 +    NS_ENSURE_TRUE(mInputSource, false);
   1.162 +    return GetStringProperty(kTISPropertyLocalizedName, aName);
   1.163 +  }
   1.164 +
   1.165 +  bool GetInputSourceID(CFStringRef &aID)
   1.166 +  {
   1.167 +    NS_ENSURE_TRUE(mInputSource, false);
   1.168 +    return GetStringProperty(kTISPropertyInputSourceID, aID);
   1.169 +  }
   1.170 +
   1.171 +  bool GetInputSourceID(nsAString &aID)
   1.172 +  {
   1.173 +    NS_ENSURE_TRUE(mInputSource, false);
   1.174 +    return GetStringProperty(kTISPropertyInputSourceID, aID);
   1.175 +  }
   1.176 +
   1.177 +  bool GetBundleID(CFStringRef &aBundleID)
   1.178 +  {
   1.179 +    NS_ENSURE_TRUE(mInputSource, false);
   1.180 +    return GetStringProperty(kTISPropertyBundleID, aBundleID);
   1.181 +  }
   1.182 +
   1.183 +  bool GetBundleID(nsAString &aBundleID)
   1.184 +  {
   1.185 +    NS_ENSURE_TRUE(mInputSource, false);
   1.186 +    return GetStringProperty(kTISPropertyBundleID, aBundleID);
   1.187 +  }
   1.188 +
   1.189 +  bool GetInputSourceType(CFStringRef &aType)
   1.190 +  {
   1.191 +    NS_ENSURE_TRUE(mInputSource, false);
   1.192 +    return GetStringProperty(kTISPropertyInputSourceType, aType);
   1.193 +  }
   1.194 +
   1.195 +  bool GetInputSourceType(nsAString &aType)
   1.196 +  {
   1.197 +    NS_ENSURE_TRUE(mInputSource, false);
   1.198 +    return GetStringProperty(kTISPropertyInputSourceType, aType);
   1.199 +  }
   1.200 +
   1.201 +  bool IsForRTLLanguage();
   1.202 +  bool IsInitializedByCurrentInputSource();
   1.203 +
   1.204 +  enum {
   1.205 +    // 40 is an actual result of the ::LMGetKbdType() when we connect an
   1.206 +    // unknown keyboard and set the keyboard type to ANSI manually on the
   1.207 +    // set up dialog.
   1.208 +    eKbdType_ANSI = 40
   1.209 +  };
   1.210 +
   1.211 +  void Select();
   1.212 +  void Clear();
   1.213 +
   1.214 +  /**
   1.215 +   * InitKeyEvent() initializes aKeyEvent for aNativeKeyEvent.
   1.216 +   *
   1.217 +   * @param aNativeKeyEvent       A native key event for which you want to
   1.218 +   *                              dispatch a Gecko key event.
   1.219 +   * @param aKeyEvent             The result -- a Gecko key event initialized
   1.220 +   *                              from the native key event.
   1.221 +   * @param aInsertString         If caller expects that the event will cause
   1.222 +   *                              a character to be input (say in an editor),
   1.223 +   *                              the caller should set this.  Otherwise,
   1.224 +   *                              if caller sets null to this, this method will
   1.225 +   *                              compute the character to be input from
   1.226 +   *                              characters of aNativeKeyEvent.
   1.227 +   */
   1.228 +  void InitKeyEvent(NSEvent *aNativeKeyEvent, WidgetKeyboardEvent& aKeyEvent,
   1.229 +                    const nsAString *aInsertString = nullptr);
   1.230 +
   1.231 +  /**
   1.232 +   * ComputeGeckoKeyCode() returns Gecko keycode for aNativeKeyCode on current
   1.233 +   * keyboard layout.
   1.234 +   *
   1.235 +   * @param aNativeKeyCode        A native keycode.
   1.236 +   * @param aKbType               A native Keyboard Type value.  Typically,
   1.237 +   *                              this is a result of ::LMGetKbdType().
   1.238 +   * @param aCmdIsPressed         TRUE if Cmd key is pressed.  Otherwise, FALSE.
   1.239 +   * @return                      The computed Gecko keycode.
   1.240 +   */
   1.241 +  uint32_t ComputeGeckoKeyCode(UInt32 aNativeKeyCode, UInt32 aKbType,
   1.242 +                               bool aCmdIsPressed);
   1.243 +
   1.244 +  /**
   1.245 +   * ComputeGeckoKeyNameIndex() returns Gecko key name index for the key.
   1.246 +   *
   1.247 +   * @param aNativeKeyCode        A native keycode.
   1.248 +   */
   1.249 +  static KeyNameIndex ComputeGeckoKeyNameIndex(UInt32 aNativeKeyCode);
   1.250 +
   1.251 +protected:
   1.252 +  /**
   1.253 +   * TranslateToString() computes the inputted text from the native keyCode,
   1.254 +   * modifier flags and keyboard type.
   1.255 +   *
   1.256 +   * @param aKeyCode              A native keyCode.
   1.257 +   * @param aModifiers            Combination of native modifier flags.
   1.258 +   * @param aKbType               A native Keyboard Type value.  Typically,
   1.259 +   *                              this is a result of ::LMGetKbdType().
   1.260 +   * @param aStr                  Result, i.e., inputted text.
   1.261 +   *                              The result can be two or more characters.
   1.262 +   * @return                      If succeeded, TRUE.  Otherwise, FALSE.
   1.263 +   *                              Even if TRUE, aStr can be empty string.
   1.264 +   */
   1.265 +  bool TranslateToString(UInt32 aKeyCode, UInt32 aModifiers,
   1.266 +                           UInt32 aKbType, nsAString &aStr);
   1.267 +
   1.268 +  /**
   1.269 +   * TranslateToChar() computes the inputted character from the native keyCode,
   1.270 +   * modifier flags and keyboard type.  If two or more characters would be
   1.271 +   * input, this returns 0.
   1.272 +   *
   1.273 +   * @param aKeyCode              A native keyCode.
   1.274 +   * @param aModifiers            Combination of native modifier flags.
   1.275 +   * @param aKbType               A native Keyboard Type value.  Typically,
   1.276 +   *                              this is a result of ::LMGetKbdType().
   1.277 +   * @return                      If succeeded and the result is one character,
   1.278 +   *                              returns the charCode of it.  Otherwise,
   1.279 +   *                              returns 0.
   1.280 +   */
   1.281 +  uint32_t TranslateToChar(UInt32 aKeyCode, UInt32 aModifiers, UInt32 aKbType);
   1.282 +
   1.283 +  /**
   1.284 +   * InitKeyPressEvent() initializes aKeyEvent for aNativeKeyEvent.
   1.285 +   * Don't call this method when aKeyEvent isn't NS_KEY_PRESS.
   1.286 +   *
   1.287 +   * @param aNativeKeyEvent       A native key event for which you want to
   1.288 +   *                              dispatch a Gecko key event.
   1.289 +   * @param aInsertChar           A character to be input in an editor by the
   1.290 +   *                              event.
   1.291 +   * @param aKeyEvent             The result -- a Gecko key event initialized
   1.292 +   *                              from the native key event.  This must be
   1.293 +   *                              NS_KEY_PRESS event.
   1.294 +   * @param aKbType               A native Keyboard Type value.  Typically,
   1.295 +   *                              this is a result of ::LMGetKbdType().
   1.296 +   */
   1.297 +  void InitKeyPressEvent(NSEvent *aNativeKeyEvent,
   1.298 +                         char16_t aInsertChar,
   1.299 +                         WidgetKeyboardEvent& aKeyEvent,
   1.300 +                         UInt32 aKbType);
   1.301 +
   1.302 +  bool GetBoolProperty(const CFStringRef aKey);
   1.303 +  bool GetStringProperty(const CFStringRef aKey, CFStringRef &aStr);
   1.304 +  bool GetStringProperty(const CFStringRef aKey, nsAString &aStr);
   1.305 +
   1.306 +  TISInputSourceRef mInputSource;
   1.307 +  TISInputSourceRef mKeyboardLayout;
   1.308 +  CFArrayRef mInputSourceList;
   1.309 +  const UCKeyboardLayout* mUCKeyboardLayout;
   1.310 +  int8_t mIsRTL;
   1.311 +
   1.312 +  bool mOverrideKeyboard;
   1.313 +};
   1.314 +
   1.315 +/**
   1.316 + * TextInputHandlerBase is a base class of PluginTextInputHandler,
   1.317 + * IMEInputHandler and TextInputHandler.  Utility methods should be implemented
   1.318 + * this level.
   1.319 + */
   1.320 +
   1.321 +class TextInputHandlerBase
   1.322 +{
   1.323 +public:
   1.324 +  nsrefcnt AddRef()
   1.325 +  {
   1.326 +    NS_PRECONDITION(int32_t(mRefCnt) >= 0, "mRefCnt is negative");
   1.327 +    ++mRefCnt;
   1.328 +    NS_LOG_ADDREF(this, mRefCnt, "TextInputHandlerBase", sizeof(*this));
   1.329 +    return mRefCnt;
   1.330 +  }
   1.331 +  nsrefcnt Release()
   1.332 +  {
   1.333 +    NS_PRECONDITION(mRefCnt != 0, "mRefCnt is alrady zero");
   1.334 +    --mRefCnt;
   1.335 +    NS_LOG_RELEASE(this, mRefCnt, "TextInputHandlerBase");
   1.336 +    if (mRefCnt == 0) {
   1.337 +        mRefCnt = 1; /* stabilize */
   1.338 +        delete this;
   1.339 +        return 0;
   1.340 +    }
   1.341 +    return mRefCnt;
   1.342 +  }
   1.343 +
   1.344 +  /**
   1.345 +   * DispatchEvent() dispatches aEvent on mWidget.
   1.346 +   *
   1.347 +   * @param aEvent                An event which you want to dispatch.
   1.348 +   * @return                      TRUE if the event is consumed by web contents
   1.349 +   *                              or chrome contents.  Otherwise, FALSE.
   1.350 +   */
   1.351 +  bool DispatchEvent(WidgetGUIEvent& aEvent);
   1.352 +
   1.353 +  /**
   1.354 +   * SetSelection() dispatches NS_SELECTION_SET event for the aRange.
   1.355 +   *
   1.356 +   * @param aRange                The range which will be selected.
   1.357 +   * @return                      TRUE if setting selection is succeeded and
   1.358 +   *                              the widget hasn't been destroyed.
   1.359 +   *                              Otherwise, FALSE.
   1.360 +   */
   1.361 +  bool SetSelection(NSRange& aRange);
   1.362 +
   1.363 +  /**
   1.364 +   * InitKeyEvent() initializes aKeyEvent for aNativeKeyEvent.
   1.365 +   *
   1.366 +   * @param aNativeKeyEvent       A native key event for which you want to
   1.367 +   *                              dispatch a Gecko key event.
   1.368 +   * @param aKeyEvent             The result -- a Gecko key event initialized
   1.369 +   *                              from the native key event.
   1.370 +   * @param aInsertString         If caller expects that the event will cause
   1.371 +   *                              a character to be input (say in an editor),
   1.372 +   *                              the caller should set this.  Otherwise,
   1.373 +   *                              if caller sets null to this, this method will
   1.374 +   *                              compute the character to be input from
   1.375 +   *                              characters of aNativeKeyEvent.
   1.376 +   */
   1.377 +  void InitKeyEvent(NSEvent *aNativeKeyEvent, WidgetKeyboardEvent& aKeyEvent,
   1.378 +                    const nsAString *aInsertString = nullptr);
   1.379 +
   1.380 +  /**
   1.381 +   * SynthesizeNativeKeyEvent() is an implementation of
   1.382 +   * nsIWidget::SynthesizeNativeKeyEvent().  See the document in nsIWidget.h
   1.383 +   * for the detail.
   1.384 +   */
   1.385 +  nsresult SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
   1.386 +                                    int32_t aNativeKeyCode,
   1.387 +                                    uint32_t aModifierFlags,
   1.388 +                                    const nsAString& aCharacters,
   1.389 +                                    const nsAString& aUnmodifiedCharacters);
   1.390 +
   1.391 +  /**
   1.392 +   * Utility method intended for testing. Attempts to construct a native key
   1.393 +   * event that would have been generated during an actual key press. This
   1.394 +   * *does not dispatch* the native event. Instead, it is attached to the
   1.395 +   * |mNativeKeyEvent| field of the Gecko event that is passed in.
   1.396 +   * @param aKeyEvent  Gecko key event to attach the native event to
   1.397 +   */
   1.398 +  NS_IMETHOD AttachNativeKeyEvent(WidgetKeyboardEvent& aKeyEvent);
   1.399 +
   1.400 +  /**
   1.401 +   * GetWindowLevel() returns the window level of current focused (in Gecko)
   1.402 +   * window.  E.g., if an <input> element in XUL panel has focus, this returns
   1.403 +   * the XUL panel's window level.
   1.404 +   */
   1.405 +  NSInteger GetWindowLevel();
   1.406 +
   1.407 +  /**
   1.408 +   * IsSpecialGeckoKey() checks whether aNativeKeyCode is mapped to a special
   1.409 +   * Gecko keyCode.  A key is "special" if it isn't used for text input.
   1.410 +   *
   1.411 +   * @param aNativeKeyCode        A native keycode.
   1.412 +   * @return                      If the keycode is mapped to a special key,
   1.413 +   *                              TRUE.  Otherwise, FALSE.
   1.414 +   */
   1.415 +  static bool IsSpecialGeckoKey(UInt32 aNativeKeyCode);
   1.416 +
   1.417 +
   1.418 +  /**
   1.419 +   * EnableSecureEventInput() and DisableSecureEventInput() wrap the Carbon
   1.420 +   * Event Manager APIs with the same names.  In addition they keep track of
   1.421 +   * how many times we've called them (in the same process) -- unlike the
   1.422 +   * Carbon Event Manager APIs, which only keep track of how many times they've
   1.423 +   * been called from any and all processes.
   1.424 +   *
   1.425 +   * The Carbon Event Manager's IsSecureEventInputEnabled() returns whether
   1.426 +   * secure event input mode is enabled (in any process).  This class's
   1.427 +   * IsSecureEventInputEnabled() returns whether we've made any calls to
   1.428 +   * EnableSecureEventInput() that are not (yet) offset by the calls we've
   1.429 +   * made to DisableSecureEventInput().
   1.430 +   */
   1.431 +  static void EnableSecureEventInput();
   1.432 +  static void DisableSecureEventInput();
   1.433 +  static bool IsSecureEventInputEnabled();
   1.434 +
   1.435 +  /**
   1.436 +   * EnsureSecureEventInputDisabled() calls DisableSecureEventInput() until
   1.437 +   * our call count becomes 0.
   1.438 +   */
   1.439 +  static void EnsureSecureEventInputDisabled();
   1.440 +
   1.441 +protected:
   1.442 +  nsAutoRefCnt mRefCnt;
   1.443 +
   1.444 +public:
   1.445 +   /**
   1.446 +   * mWidget must not be destroyed without OnDestroyWidget being called.
   1.447 +   *
   1.448 +   * @param aDestroyingWidget     Destroying widget.  This might not be mWidget.
   1.449 +   * @return                      This result doesn't have any meaning for
   1.450 +   *                              callers.  When aDstroyingWidget isn't the same
   1.451 +   *                              as mWidget, FALSE.  Then, inherited methods in
   1.452 +   *                              sub classes should return from this method
   1.453 +   *                              without cleaning up.
   1.454 +   */
   1.455 +  virtual bool OnDestroyWidget(nsChildView* aDestroyingWidget);
   1.456 +
   1.457 +protected:
   1.458 +  // The creater of this instance and client.
   1.459 +  // This must not be null after initialized until OnDestroyWidget() is called.
   1.460 +  nsChildView* mWidget; // [WEAK]
   1.461 +
   1.462 +  // The native view for mWidget.
   1.463 +  // This view handles the actual text inputting.
   1.464 +  NSView<mozView>* mView; // [STRONG]
   1.465 +
   1.466 +  TextInputHandlerBase(nsChildView* aWidget, NSView<mozView> *aNativeView);
   1.467 +  virtual ~TextInputHandlerBase();
   1.468 +
   1.469 +  bool Destroyed() { return !mWidget; }
   1.470 +
   1.471 +  /**
   1.472 +   * mCurrentKeyEvent indicates what key event we are handling.  While
   1.473 +   * handling a native keydown event, we need to store the event for insertText,
   1.474 +   * doCommandBySelector and various action message handlers of NSResponder
   1.475 +   * such as [NSResponder insertNewline:sender].
   1.476 +   */
   1.477 +  struct KeyEventState
   1.478 +  {
   1.479 +    // Handling native key event
   1.480 +    NSEvent* mKeyEvent;
   1.481 +    // Whether keydown event was consumed by web contents or chrome contents.
   1.482 +    bool mKeyDownHandled;
   1.483 +    // Whether keypress event was dispatched for mKeyEvent.
   1.484 +    bool mKeyPressDispatched;
   1.485 +    // Whether keypress event was consumed by web contents or chrome contents.
   1.486 +    bool mKeyPressHandled;
   1.487 +    // Whether the key event causes other key events via IME or something.
   1.488 +    bool mCausedOtherKeyEvents;
   1.489 +
   1.490 +    KeyEventState() : mKeyEvent(nullptr)
   1.491 +    {
   1.492 +      Clear();
   1.493 +    }    
   1.494 +
   1.495 +    KeyEventState(NSEvent* aNativeKeyEvent) : mKeyEvent(nullptr)
   1.496 +    {
   1.497 +      Clear();
   1.498 +      Set(aNativeKeyEvent);
   1.499 +    }
   1.500 +
   1.501 +    KeyEventState(const KeyEventState &aOther) : mKeyEvent(nullptr)
   1.502 +    {
   1.503 +      Clear();
   1.504 +      if (aOther.mKeyEvent) {
   1.505 +        mKeyEvent = [aOther.mKeyEvent retain];
   1.506 +      }
   1.507 +      mKeyDownHandled = aOther.mKeyDownHandled;
   1.508 +      mKeyPressDispatched = aOther.mKeyPressDispatched;
   1.509 +      mKeyPressHandled = aOther.mKeyPressHandled;
   1.510 +      mCausedOtherKeyEvents = aOther.mCausedOtherKeyEvents;
   1.511 +    }
   1.512 +
   1.513 +    ~KeyEventState()
   1.514 +    {
   1.515 +      Clear();
   1.516 +    }
   1.517 +
   1.518 +    void Set(NSEvent* aNativeKeyEvent)
   1.519 +    {
   1.520 +      NS_PRECONDITION(aNativeKeyEvent, "aNativeKeyEvent must not be NULL");
   1.521 +      Clear();
   1.522 +      mKeyEvent = [aNativeKeyEvent retain];
   1.523 +    }
   1.524 +
   1.525 +    void Clear()
   1.526 +    {
   1.527 +      if (mKeyEvent) {
   1.528 +        [mKeyEvent release];
   1.529 +        mKeyEvent = nullptr;
   1.530 +      }
   1.531 +      mKeyDownHandled = false;
   1.532 +      mKeyPressDispatched = false;
   1.533 +      mKeyPressHandled = false;
   1.534 +      mCausedOtherKeyEvents = false;
   1.535 +    }
   1.536 +
   1.537 +    bool IsDefaultPrevented() const
   1.538 +    {
   1.539 +      return mKeyDownHandled || mKeyPressHandled || mCausedOtherKeyEvents;
   1.540 +    }
   1.541 +
   1.542 +    bool CanDispatchKeyPressEvent() const
   1.543 +    {
   1.544 +      return !mKeyPressDispatched && !IsDefaultPrevented();
   1.545 +    }
   1.546 +  };
   1.547 +
   1.548 +  /**
   1.549 +   * Helper class for guaranteeing cleaning mCurrentKeyEvent
   1.550 +   */
   1.551 +  class AutoKeyEventStateCleaner
   1.552 +  {
   1.553 +  public:
   1.554 +    AutoKeyEventStateCleaner(TextInputHandlerBase* aHandler) :
   1.555 +      mHandler(aHandler)
   1.556 +    {
   1.557 +    }
   1.558 +
   1.559 +    ~AutoKeyEventStateCleaner()
   1.560 +    {
   1.561 +      mHandler->RemoveCurrentKeyEvent();
   1.562 +    }
   1.563 +  private:
   1.564 +    nsRefPtr<TextInputHandlerBase> mHandler;
   1.565 +  };
   1.566 +
   1.567 +  /**
   1.568 +   * mCurrentKeyEvents stores all key events which are being processed.
   1.569 +   * When we call interpretKeyEvents, IME may generate other key events.
   1.570 +   * mCurrentKeyEvents[0] is the latest key event.
   1.571 +   */
   1.572 +  nsTArray<KeyEventState*> mCurrentKeyEvents;
   1.573 +
   1.574 +  /**
   1.575 +   * mFirstKeyEvent must be used for first key event.  This member prevents
   1.576 +   * memory fragmentation for most key events.
   1.577 +   */
   1.578 +  KeyEventState mFirstKeyEvent;
   1.579 +
   1.580 +  /**
   1.581 +   * PushKeyEvent() adds the current key event to mCurrentKeyEvents.
   1.582 +   */
   1.583 +  KeyEventState* PushKeyEvent(NSEvent* aNativeKeyEvent)
   1.584 +  {
   1.585 +    uint32_t nestCount = mCurrentKeyEvents.Length();
   1.586 +    for (uint32_t i = 0; i < nestCount; i++) {
   1.587 +      // When the key event is caused by another key event, all key events
   1.588 +      // which are being handled should be marked as "consumed".
   1.589 +      mCurrentKeyEvents[i]->mCausedOtherKeyEvents = true;
   1.590 +    }
   1.591 +
   1.592 +    KeyEventState* keyEvent = nullptr;
   1.593 +    if (nestCount == 0) {
   1.594 +      mFirstKeyEvent.Set(aNativeKeyEvent);
   1.595 +      keyEvent = &mFirstKeyEvent;
   1.596 +    } else {
   1.597 +      keyEvent = new KeyEventState(aNativeKeyEvent);
   1.598 +    }
   1.599 +    return *mCurrentKeyEvents.AppendElement(keyEvent);
   1.600 +  }
   1.601 +
   1.602 +  /**
   1.603 +   * RemoveCurrentKeyEvent() removes the current key event from
   1.604 +   * mCurrentKeyEvents.
   1.605 +   */
   1.606 +  void RemoveCurrentKeyEvent()
   1.607 +  {
   1.608 +    NS_ASSERTION(mCurrentKeyEvents.Length() > 0,
   1.609 +                 "RemoveCurrentKeyEvent() is called unexpectedly");
   1.610 +    KeyEventState* keyEvent = GetCurrentKeyEvent();
   1.611 +    mCurrentKeyEvents.RemoveElementAt(mCurrentKeyEvents.Length() - 1);
   1.612 +    if (keyEvent == &mFirstKeyEvent) {
   1.613 +      keyEvent->Clear();
   1.614 +    } else {
   1.615 +      delete keyEvent;
   1.616 +    }
   1.617 +  }
   1.618 +
   1.619 +  /**
   1.620 +   * GetCurrentKeyEvent() returns current processing key event.
   1.621 +   */
   1.622 +  KeyEventState* GetCurrentKeyEvent()
   1.623 +  {
   1.624 +    if (mCurrentKeyEvents.Length() == 0) {
   1.625 +      return nullptr;
   1.626 +    }
   1.627 +    return mCurrentKeyEvents[mCurrentKeyEvents.Length() - 1];
   1.628 +  }
   1.629 +
   1.630 +  /**
   1.631 +   * IsPrintableChar() checks whether the unicode character is
   1.632 +   * a non-printable ASCII character or not.  Note that this returns
   1.633 +   * TRUE even if aChar is a non-printable UNICODE character.
   1.634 +   *
   1.635 +   * @param aChar                 A unicode character.
   1.636 +   * @return                      TRUE if aChar is a printable ASCII character
   1.637 +   *                              or a unicode character.  Otherwise, i.e,
   1.638 +   *                              if aChar is a non-printable ASCII character,
   1.639 +   *                              FALSE.
   1.640 +   */
   1.641 +  static bool IsPrintableChar(char16_t aChar);
   1.642 +
   1.643 +  /**
   1.644 +   * IsNormalCharInputtingEvent() checks whether aKeyEvent causes text input.
   1.645 +   *
   1.646 +   * @param aKeyEvent             A key event.
   1.647 +   * @return                      TRUE if the key event causes text input.
   1.648 +   *                              Otherwise, FALSE.
   1.649 +   */
   1.650 +  static bool IsNormalCharInputtingEvent(const WidgetKeyboardEvent& aKeyEvent);
   1.651 +
   1.652 +  /**
   1.653 +   * IsModifierKey() checks whether the native keyCode is for a modifier key.
   1.654 +   *
   1.655 +   * @param aNativeKeyCode        A native keyCode.
   1.656 +   * @return                      TRUE if aNativeKeyCode is for a modifier key.
   1.657 +   *                              Otherwise, FALSE.
   1.658 +   */
   1.659 +  static bool IsModifierKey(UInt32 aNativeKeyCode);
   1.660 +
   1.661 +private:
   1.662 +  struct KeyboardLayoutOverride {
   1.663 +    int32_t mKeyboardLayout;
   1.664 +    bool mOverrideEnabled;
   1.665 +
   1.666 +    KeyboardLayoutOverride() :
   1.667 +      mKeyboardLayout(0), mOverrideEnabled(false)
   1.668 +    {
   1.669 +    }
   1.670 +  };
   1.671 +
   1.672 +  KeyboardLayoutOverride mKeyboardOverride;
   1.673 +
   1.674 +  static int32_t sSecureEventInputCount;
   1.675 +};
   1.676 +
   1.677 +/**
   1.678 + * PluginTextInputHandler handles text input events for plugins.
   1.679 + */
   1.680 +
   1.681 +class PluginTextInputHandler : public TextInputHandlerBase
   1.682 +{
   1.683 +public:
   1.684 +
   1.685 +  /**
   1.686 +   * When starting complex text input for current event on plugin, this is
   1.687 +   * called.  See also the comment of StartComplexTextInputForCurrentEvent() of
   1.688 +   * nsIPluginWidget.
   1.689 +   */
   1.690 +  nsresult StartComplexTextInputForCurrentEvent()
   1.691 +  {
   1.692 +    mPluginComplexTextInputRequested = true;
   1.693 +    return NS_OK;
   1.694 +  }
   1.695 +
   1.696 +  /**
   1.697 +   * HandleKeyDownEventForPlugin() handles aNativeKeyEvent.
   1.698 +   *
   1.699 +   * @param aNativeKeyEvent       A native NSKeyDown event.
   1.700 +   */
   1.701 +  void HandleKeyDownEventForPlugin(NSEvent* aNativeKeyEvent);
   1.702 +
   1.703 +  /**
   1.704 +   * HandleKeyUpEventForPlugin() handles aNativeKeyEvent.
   1.705 +   *
   1.706 +   * @param aNativeKeyEvent       A native NSKeyUp event.
   1.707 +   */
   1.708 +  void HandleKeyUpEventForPlugin(NSEvent* aNativeKeyEvent);
   1.709 +
   1.710 +  /**
   1.711 +   * ConvertCocoaKeyEventToNPCocoaEvent() converts aCocoaEvent to NPCocoaEvent.
   1.712 +   *
   1.713 +   * @param aCocoaEvent           A native key event.
   1.714 +   * @param aPluginEvent          The result.
   1.715 +   */
   1.716 +  static void ConvertCocoaKeyEventToNPCocoaEvent(NSEvent* aCocoaEvent,
   1.717 +                                                 NPCocoaEvent& aPluginEvent);
   1.718 +
   1.719 +#ifndef __LP64__
   1.720 +
   1.721 +  /**
   1.722 +   * InstallPluginKeyEventsHandler() is called when initializing process.
   1.723 +   * RemovePluginKeyEventsHandler() is called when finalizing process.
   1.724 +   * These methods initialize/finalize global resource for handling events for
   1.725 +   * plugins.
   1.726 +   */
   1.727 +  static void InstallPluginKeyEventsHandler();
   1.728 +  static void RemovePluginKeyEventsHandler();
   1.729 +
   1.730 +  /**
   1.731 +   * This must be called before first key/IME event for plugins.
   1.732 +   * This method initializes IMKInputSession methods swizzling.
   1.733 +   */
   1.734 +  static void SwizzleMethods();
   1.735 +
   1.736 +  /**
   1.737 +   * When a composition starts or finishes, this is called.
   1.738 +   */
   1.739 +  void SetPluginTSMInComposition(bool aInComposition)
   1.740 +  {
   1.741 +    mPluginTSMInComposition = aInComposition;
   1.742 +  }
   1.743 +
   1.744 +#endif // #ifndef __LP64__
   1.745 +
   1.746 +protected:
   1.747 +  bool mIgnoreNextKeyUpEvent;
   1.748 +
   1.749 +  PluginTextInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView);
   1.750 +  ~PluginTextInputHandler();
   1.751 +
   1.752 +private:
   1.753 +
   1.754 +#ifndef __LP64__
   1.755 +  TSMDocumentID mPluginTSMDoc;
   1.756 +
   1.757 +  bool mPluginTSMInComposition;
   1.758 +#endif // #ifndef __LP64__
   1.759 +
   1.760 +  bool mPluginComplexTextInputRequested;
   1.761 +
   1.762 +  /**
   1.763 +   * DispatchCocoaNPAPITextEvent() dispatches a text event for Cocoa plugin.
   1.764 +   *
   1.765 +   * @param aString               A string inputted by the dispatching event.
   1.766 +   * @return                      TRUE if the dispatched event was consumed.
   1.767 +   *                              Otherwise, FALSE.
   1.768 +   */
   1.769 +  bool DispatchCocoaNPAPITextEvent(NSString* aString);
   1.770 +
   1.771 +  /**
   1.772 +   * Whether the plugin is in composition or not.
   1.773 +   * On 32bit build, this returns the state of mPluginTSMInComposition.
   1.774 +   * On 64bit build, this returns ComplexTextInputPanel's state.
   1.775 +   *
   1.776 +   * @return                      TRUE if plugin is in composition.  Otherwise,
   1.777 +   *                              FALSE.
   1.778 +   */
   1.779 +  bool IsInPluginComposition();
   1.780 +
   1.781 +#ifndef __LP64__
   1.782 +
   1.783 +  /**
   1.784 +   * Create a TSM document for use with plugins, so that we can support IME in
   1.785 +   * them.  Once it's created, if need be (re)activate it.  Some plugins (e.g.
   1.786 +   * the Flash plugin running in Camino) don't create their own TSM document --
   1.787 +   * without which IME can't work.  Others (e.g. the Flash plugin running in
   1.788 +   * Firefox) create a TSM document that (somehow) makes the input window behave
   1.789 +   * badly when it contains more than one kind of input (say Hiragana and
   1.790 +   * Romaji).  (We can't just use the per-NSView TSM documents that Cocoa
   1.791 +   * provides (those created and managed by the NSTSMInputContext class) -- for
   1.792 +   * some reason TSMProcessRawKeyEvent() doesn't work with them.)
   1.793 +   */
   1.794 +  void ActivatePluginTSMDocument();
   1.795 +
   1.796 +  /**
   1.797 +   * HandleCarbonPluginKeyEvent() handles the aKeyEvent.  This is called by
   1.798 +   * PluginKeyEventsHandler().
   1.799 +   *
   1.800 +   * @param aKeyEvent             A native Carbon event.
   1.801 +   */
   1.802 +  void HandleCarbonPluginKeyEvent(EventRef aKeyEvent);
   1.803 +
   1.804 +  /**
   1.805 +   * Target for text services events sent as the result of calls made to
   1.806 +   * TSMProcessRawKeyEvent() in HandleKeyDownEventForPlugin() when a plugin has
   1.807 +   * the focus.  The calls to TSMProcessRawKeyEvent() short-circuit Cocoa-based
   1.808 +   * IME (which would otherwise interfere with our efforts) and allow Carbon-
   1.809 +   * based IME to work in plugins (via the NPAPI).  This strategy doesn't cause
   1.810 +   * trouble for plugins that (like the Java Embedding Plugin) bypass the NPAPI
   1.811 +   * to get their keyboard events and do their own Cocoa-based IME.
   1.812 +   */
   1.813 +  static OSStatus PluginKeyEventsHandler(EventHandlerCallRef aHandlerRef,
   1.814 +                                         EventRef aEvent,
   1.815 +                                         void *aUserData);
   1.816 +
   1.817 +  static EventHandlerRef sPluginKeyEventsHandler;
   1.818 +
   1.819 +#endif // #ifndef __LP64__
   1.820 +};
   1.821 +
   1.822 +/**
   1.823 + * IMEInputHandler manages:
   1.824 + *   1. The IME/keyboard layout statement of nsChildView.
   1.825 + *   2. The IME composition statement of nsChildView.
   1.826 + * And also provides the methods which controls the current IME transaction of
   1.827 + * the instance.
   1.828 + *
   1.829 + * Note that an nsChildView handles one or more NSView's events.  E.g., even if
   1.830 + * a text editor on XUL panel element, the input events handled on the parent
   1.831 + * (or its ancestor) widget handles it (the native focus is set to it).  The
   1.832 + * actual focused view is notified by OnFocusChangeInGecko.
   1.833 + */
   1.834 +
   1.835 +class IMEInputHandler : public PluginTextInputHandler
   1.836 +{
   1.837 +public:
   1.838 +  virtual bool OnDestroyWidget(nsChildView* aDestroyingWidget);
   1.839 +
   1.840 +  virtual void OnFocusChangeInGecko(bool aFocus);
   1.841 +
   1.842 +  void OnSelectionChange() { mSelectedRange.location = NSNotFound; }
   1.843 +
   1.844 +  /**
   1.845 +   * DispatchTextEvent() dispatches a text event on mWidget.
   1.846 +   *
   1.847 +   * @param aText                 User text input.
   1.848 +   * @param aAttrString           An NSAttributedString instance which indicates
   1.849 +   *                              current composition string.
   1.850 +   * @param aSelectedRange        Current selected range (or caret position).
   1.851 +   * @param aDoCommit             TRUE if the composition string should be
   1.852 +   *                              committed.  Otherwise, FALSE.
   1.853 +   */
   1.854 +  bool DispatchTextEvent(const nsString& aText,
   1.855 +                           NSAttributedString* aAttrString,
   1.856 +                           NSRange& aSelectedRange,
   1.857 +                           bool aDoCommit);
   1.858 +
   1.859 +  /**
   1.860 +   * SetMarkedText() is a handler of setMarkedText of NSTextInput.
   1.861 +   *
   1.862 +   * @param aAttrString           This mut be an instance of NSAttributedString.
   1.863 +   *                              If the aString parameter to
   1.864 +   *                              [ChildView setMarkedText:setSelectedRange:]
   1.865 +   *                              isn't an instance of NSAttributedString,
   1.866 +   *                              create an NSAttributedString from it and pass
   1.867 +   *                              that instead.
   1.868 +   * @param aSelectedRange        Current selected range (or caret position).
   1.869 +   * @param aReplacementRange     The range which will be replaced with the
   1.870 +   *                              aAttrString instead of current marked range.
   1.871 +   */
   1.872 +  void SetMarkedText(NSAttributedString* aAttrString,
   1.873 +                     NSRange& aSelectedRange,
   1.874 +                     NSRange* aReplacementRange = nullptr);
   1.875 +
   1.876 +  /**
   1.877 +   * ConversationIdentifier() returns an ID for the current editor.  The ID is
   1.878 +   * guaranteed to be unique among currently existing editors.  But it might be
   1.879 +   * the same as the ID of an editor that has already been destroyed.
   1.880 +   *
   1.881 +   * @return                      An identifier of current focused editor.
   1.882 +   */
   1.883 +  NSInteger ConversationIdentifier();
   1.884 +
   1.885 +  /**
   1.886 +   * GetAttributedSubstringFromRange() returns an NSAttributedString instance
   1.887 +   * which is allocated as autorelease for aRange.
   1.888 +   *
   1.889 +   * @param aRange                The range of string which you want.
   1.890 +   * @param aActualRange          The actual range of the result.
   1.891 +   * @return                      The string in aRange.  If the string is empty,
   1.892 +   *                              this returns nil.  If succeeded, this returns
   1.893 +   *                              an instance which is allocated as autorelease.
   1.894 +   *                              If this has some troubles, returns nil.
   1.895 +   */
   1.896 +  NSAttributedString* GetAttributedSubstringFromRange(
   1.897 +                        NSRange& aRange,
   1.898 +                        NSRange* aActualRange = nullptr);
   1.899 +
   1.900 +  /**
   1.901 +   * SelectedRange() returns current selected range.
   1.902 +   *
   1.903 +   * @return                      If an editor has focus, this returns selection
   1.904 +   *                              range in the editor.  Otherwise, this returns
   1.905 +   *                              selection range  in the focused document.
   1.906 +   */
   1.907 +  NSRange SelectedRange();
   1.908 +
   1.909 +  /**
   1.910 +   * FirstRectForCharacterRange() returns first *character* rect in the range.
   1.911 +   * Cocoa needs the first line rect in the range, but we cannot compute it
   1.912 +   * on current implementation.
   1.913 +   *
   1.914 +   * @param aRange                A range of text to examine.  Its position is
   1.915 +   *                              an offset from the beginning of the focused
   1.916 +   *                              editor or document.
   1.917 +   * @param aActualRange          If this is not null, this returns the actual
   1.918 +   *                              range used for computing the result.
   1.919 +   * @return                      An NSRect containing the first character in
   1.920 +   *                              aRange, in screen coordinates.
   1.921 +   *                              If the length of aRange is 0, the width will
   1.922 +   *                              be 0.
   1.923 +   */
   1.924 +  NSRect FirstRectForCharacterRange(NSRange& aRange,
   1.925 +                                    NSRange* aActualRange = nullptr);
   1.926 +
   1.927 +  /**
   1.928 +   * CharacterIndexForPoint() returns an offset of a character at aPoint.
   1.929 +   * XXX This isn't implemented, always returns 0.
   1.930 +   *
   1.931 +   * @param                       The point in screen coordinates.
   1.932 +   * @return                      The offset of the character at aPoint from
   1.933 +   *                              the beginning of the focused editor or
   1.934 +   *                              document.
   1.935 +   */
   1.936 +  NSUInteger CharacterIndexForPoint(NSPoint& aPoint);
   1.937 +
   1.938 +  /**
   1.939 +   * GetValidAttributesForMarkedText() returns attributes which we support.
   1.940 +   *
   1.941 +   * @return                      Always empty array for now.
   1.942 +   */
   1.943 +  NSArray* GetValidAttributesForMarkedText();
   1.944 +
   1.945 +  bool HasMarkedText();
   1.946 +  NSRange MarkedRange();
   1.947 +
   1.948 +  bool IsIMEComposing() { return mIsIMEComposing; }
   1.949 +  bool IsIMEOpened();
   1.950 +  bool IsIMEEnabled() { return mIsIMEEnabled; }
   1.951 +  bool IsASCIICapableOnly() { return mIsASCIICapableOnly; }
   1.952 +  bool IgnoreIMECommit() { return mIgnoreIMECommit; }
   1.953 +
   1.954 +  bool IgnoreIMEComposition()
   1.955 +  {
   1.956 +    // Ignore the IME composition events when we're pending to discard the
   1.957 +    // composition and we are not to handle the IME composition now.
   1.958 +    return (mPendingMethods & kDiscardIMEComposition) &&
   1.959 +           (mIsInFocusProcessing || !IsFocused());
   1.960 +  }
   1.961 +
   1.962 +  void CommitIMEComposition();
   1.963 +  void CancelIMEComposition();
   1.964 +
   1.965 +  void EnableIME(bool aEnableIME);
   1.966 +  void SetIMEOpenState(bool aOpen);
   1.967 +  void SetASCIICapableOnly(bool aASCIICapableOnly);
   1.968 +
   1.969 +  bool IsFocused();
   1.970 +
   1.971 +  static CFArrayRef CreateAllIMEModeList();
   1.972 +  static void DebugPrintAllIMEModes();
   1.973 +
   1.974 +  // Don't use ::TSMGetActiveDocument() API directly, the document may not
   1.975 +  // be what you want.
   1.976 +  static TSMDocumentID GetCurrentTSMDocumentID();
   1.977 +
   1.978 +protected:
   1.979 +  // We cannot do some jobs in the given stack by some reasons.
   1.980 +  // Following flags and the timer provide the execution pending mechanism,
   1.981 +  // See the comment in nsCocoaTextInputHandler.mm.
   1.982 +  nsCOMPtr<nsITimer> mTimer;
   1.983 +  enum {
   1.984 +    kNotifyIMEOfFocusChangeInGecko = 1,
   1.985 +    kDiscardIMEComposition         = 2,
   1.986 +    kSyncASCIICapableOnly          = 4
   1.987 +  };
   1.988 +  uint32_t mPendingMethods;
   1.989 +
   1.990 +  IMEInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView);
   1.991 +  virtual ~IMEInputHandler();
   1.992 +
   1.993 +  void ResetTimer();
   1.994 +
   1.995 +  virtual void ExecutePendingMethods();
   1.996 +
   1.997 +  /**
   1.998 +   * InsertTextAsCommittingComposition() commits current composition.  If there
   1.999 +   * is no composition, this starts a composition and commits it immediately.
  1.1000 +   *
  1.1001 +   * @param aAttrString           A string which is committed.
  1.1002 +   * @param aReplacementRange     The range which will be replaced with the
  1.1003 +   *                              aAttrString instead of current selection.
  1.1004 +   */
  1.1005 +  void InsertTextAsCommittingComposition(NSAttributedString* aAttrString,
  1.1006 +                                         NSRange* aReplacementRange);
  1.1007 +
  1.1008 +private:
  1.1009 +  // If mIsIMEComposing is true, the composition string is stored here.
  1.1010 +  NSString* mIMECompositionString;
  1.1011 +  // mLastDispatchedCompositionString stores the lastest dispatched composition
  1.1012 +  // string by compositionupdate event.
  1.1013 +  nsString mLastDispatchedCompositionString;
  1.1014 +
  1.1015 +  NSRange mMarkedRange;
  1.1016 +  NSRange mSelectedRange;
  1.1017 +
  1.1018 +  bool mIsIMEComposing;
  1.1019 +  bool mIsIMEEnabled;
  1.1020 +  bool mIsASCIICapableOnly;
  1.1021 +  bool mIgnoreIMECommit;
  1.1022 +  // This flag is enabled by OnFocusChangeInGecko, and will be cleared by
  1.1023 +  // ExecutePendingMethods.  When this is true, IsFocus() returns TRUE.  At
  1.1024 +  // that time, the focus processing in Gecko might not be finished yet.  So,
  1.1025 +  // you cannot use WidgetQueryContentEvent or something.
  1.1026 +  bool mIsInFocusProcessing;
  1.1027 +  bool mIMEHasFocus;
  1.1028 +
  1.1029 +  void KillIMEComposition();
  1.1030 +  void SendCommittedText(NSString *aString);
  1.1031 +  void OpenSystemPreferredLanguageIME();
  1.1032 +
  1.1033 +  // Pending methods
  1.1034 +  void NotifyIMEOfFocusChangeInGecko();
  1.1035 +  void DiscardIMEComposition();
  1.1036 +  void SyncASCIICapableOnly();
  1.1037 +
  1.1038 +  static bool sStaticMembersInitialized;
  1.1039 +  static CFStringRef sLatestIMEOpenedModeInputSourceID;
  1.1040 +  static void InitStaticMembers();
  1.1041 +  static void OnCurrentTextInputSourceChange(CFNotificationCenterRef aCenter,
  1.1042 +                                             void* aObserver,
  1.1043 +                                             CFStringRef aName,
  1.1044 +                                             const void* aObject,
  1.1045 +                                             CFDictionaryRef aUserInfo);
  1.1046 +
  1.1047 +  static void FlushPendingMethods(nsITimer* aTimer, void* aClosure);
  1.1048 +
  1.1049 +  /**
  1.1050 +   * ConvertToTextRangeStyle converts the given native underline style to
  1.1051 +   * our defined text range type.
  1.1052 +   *
  1.1053 +   * @param aUnderlineStyle       NSUnderlineStyleSingle or
  1.1054 +   *                              NSUnderlineStyleThick.
  1.1055 +   * @param aSelectedRange        Current selected range (or caret position).
  1.1056 +   * @return                      NS_TEXTRANGE_*.
  1.1057 +   */
  1.1058 +  uint32_t ConvertToTextRangeType(uint32_t aUnderlineStyle,
  1.1059 +                                  NSRange& aSelectedRange);
  1.1060 +
  1.1061 +  /**
  1.1062 +   * GetRangeCount() computes the range count of aAttrString.
  1.1063 +   *
  1.1064 +   * @param aAttrString           An NSAttributedString instance whose number of
  1.1065 +   *                              NSUnderlineStyleAttributeName ranges you with
  1.1066 +   *                              to know.
  1.1067 +   * @return                      The count of NSUnderlineStyleAttributeName
  1.1068 +   *                              ranges in aAttrString.
  1.1069 +   */
  1.1070 +  uint32_t GetRangeCount(NSAttributedString *aString);
  1.1071 +
  1.1072 +  /**
  1.1073 +   * CreateTextRangeArray() returns text ranges for clauses and/or caret.
  1.1074 +   *
  1.1075 +   * @param aAttrString           An NSAttributedString instance which indicates
  1.1076 +   *                              current composition string.
  1.1077 +   * @param aSelectedRange        Current selected range (or caret position).
  1.1078 +   * @return                      The result is set to the
  1.1079 +   *                              NSUnderlineStyleAttributeName ranges in
  1.1080 +   *                              aAttrString.
  1.1081 +   */
  1.1082 +  already_AddRefed<mozilla::TextRangeArray>
  1.1083 +    CreateTextRangeArray(NSAttributedString *aAttrString,
  1.1084 +                         NSRange& aSelectedRange);
  1.1085 +
  1.1086 +  /**
  1.1087 +   * InitCompositionEvent() initializes aCompositionEvent.
  1.1088 +   *
  1.1089 +   * @param aCompositionEvent     A composition event which you want to
  1.1090 +   *                              initialize.
  1.1091 +   */
  1.1092 +  void InitCompositionEvent(WidgetCompositionEvent& aCompositionEvent);
  1.1093 +
  1.1094 +  /**
  1.1095 +   * When a composition starts, OnStartIMEComposition() is called.
  1.1096 +   */
  1.1097 +  void OnStartIMEComposition();
  1.1098 +
  1.1099 +  /**
  1.1100 +   * When a composition is updated, OnUpdateIMEComposition() is called.
  1.1101 +   */
  1.1102 +  void OnUpdateIMEComposition(NSString* aIMECompositionString);
  1.1103 +
  1.1104 +  /**
  1.1105 +   * When a composition is finished, OnEndIMEComposition() is called.
  1.1106 +   */
  1.1107 +  void OnEndIMEComposition();
  1.1108 +
  1.1109 +  // The focused IME handler.  Please note that the handler might lost the
  1.1110 +  // actual focus by deactivating the application.  If we are active, this
  1.1111 +  // must have the actual focused handle.
  1.1112 +  // We cannot access to the NSInputManager during we aren't active, so, the
  1.1113 +  // focused handler can have an IME transaction even if we are deactive.
  1.1114 +  static IMEInputHandler* sFocusedIMEHandler;
  1.1115 +};
  1.1116 +
  1.1117 +/**
  1.1118 + * TextInputHandler implements the NSTextInput protocol.
  1.1119 + */
  1.1120 +class TextInputHandler : public IMEInputHandler
  1.1121 +{
  1.1122 +public:
  1.1123 +  static NSUInteger sLastModifierState;
  1.1124 +
  1.1125 +  static CFArrayRef CreateAllKeyboardLayoutList();
  1.1126 +  static void DebugPrintAllKeyboardLayouts();
  1.1127 +
  1.1128 +  TextInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView);
  1.1129 +  virtual ~TextInputHandler();
  1.1130 +
  1.1131 +  /**
  1.1132 +   * KeyDown event handler.
  1.1133 +   *
  1.1134 +   * @param aNativeEvent          A native NSKeyDown event.
  1.1135 +   * @return                      TRUE if the event is consumed by web contents
  1.1136 +   *                              or chrome contents.  Otherwise, FALSE.
  1.1137 +   */
  1.1138 +  bool HandleKeyDownEvent(NSEvent* aNativeEvent);
  1.1139 +
  1.1140 +  /**
  1.1141 +   * KeyUp event handler.
  1.1142 +   *
  1.1143 +   * @param aNativeEvent          A native NSKeyUp event.
  1.1144 +   */
  1.1145 +  void HandleKeyUpEvent(NSEvent* aNativeEvent);
  1.1146 +
  1.1147 +  /**
  1.1148 +   * FlagsChanged event handler.
  1.1149 +   *
  1.1150 +   * @param aNativeEvent          A native NSFlagsChanged event.
  1.1151 +   */
  1.1152 +  void HandleFlagsChanged(NSEvent* aNativeEvent);
  1.1153 +
  1.1154 +  /**
  1.1155 +   * Insert the string to content.  I.e., this is a text input event handler.
  1.1156 +   * If this is called during keydown event handling, this may dispatch a
  1.1157 +   * NS_KEY_PRESS event.  If this is called during composition, this commits
  1.1158 +   * the composition by the aAttrString.
  1.1159 +   *
  1.1160 +   * @param aAttrString           An inserted string.
  1.1161 +   * @param aReplacementRange     The range which will be replaced with the
  1.1162 +   *                              aAttrString instead of current selection.
  1.1163 +   */
  1.1164 +  void InsertText(NSAttributedString *aAttrString,
  1.1165 +                  NSRange* aReplacementRange = nullptr);
  1.1166 +
  1.1167 +  /**
  1.1168 +   * doCommandBySelector event handler.
  1.1169 +   *
  1.1170 +   * @param aSelector             A selector of the command.
  1.1171 +   * @return                      TRUE if the command is consumed.  Otherwise,
  1.1172 +   *                              FALSE.
  1.1173 +   */
  1.1174 +  bool DoCommandBySelector(const char* aSelector);
  1.1175 +
  1.1176 +  /**
  1.1177 +   * KeyPressWasHandled() checks whether keypress event was handled or not.
  1.1178 +   *
  1.1179 +   * @return                      TRUE if keypress event for latest native key
  1.1180 +   *                              event was handled.  Otherwise, FALSE.
  1.1181 +   *                              If this handler isn't handling any key events,
  1.1182 +   *                              always returns FALSE.
  1.1183 +   */
  1.1184 +  bool KeyPressWasHandled()
  1.1185 +  {
  1.1186 +    KeyEventState* currentKeyEvent = GetCurrentKeyEvent();
  1.1187 +    return currentKeyEvent && currentKeyEvent->mKeyPressHandled;
  1.1188 +  }
  1.1189 +
  1.1190 +protected:
  1.1191 +  // Stores the association of device dependent modifier flags with a modifier
  1.1192 +  // keyCode.  Being device dependent, this association may differ from one kind
  1.1193 +  // of hardware to the next.
  1.1194 +  struct ModifierKey
  1.1195 +  {
  1.1196 +    NSUInteger flags;
  1.1197 +    unsigned short keyCode;
  1.1198 +
  1.1199 +    ModifierKey(NSUInteger aFlags, unsigned short aKeyCode) :
  1.1200 +      flags(aFlags), keyCode(aKeyCode)
  1.1201 +    {
  1.1202 +    }
  1.1203 +
  1.1204 +    NSUInteger GetDeviceDependentFlags() const
  1.1205 +    {
  1.1206 +      return (flags & ~NSDeviceIndependentModifierFlagsMask);
  1.1207 +    }
  1.1208 +
  1.1209 +    NSUInteger GetDeviceIndependentFlags() const
  1.1210 +    {
  1.1211 +      return (flags & NSDeviceIndependentModifierFlagsMask);
  1.1212 +    }
  1.1213 +  };
  1.1214 +  typedef nsTArray<ModifierKey> ModifierKeyArray;
  1.1215 +  ModifierKeyArray mModifierKeys;
  1.1216 +
  1.1217 +  /**
  1.1218 +   * GetModifierKeyForNativeKeyCode() returns the stored ModifierKey for
  1.1219 +   * the key.
  1.1220 +   */
  1.1221 +  const ModifierKey*
  1.1222 +    GetModifierKeyForNativeKeyCode(unsigned short aKeyCode) const;
  1.1223 +
  1.1224 +  /**
  1.1225 +   * GetModifierKeyForDeviceDependentFlags() returns the stored ModifierKey for
  1.1226 +   * the device dependent flags.
  1.1227 +   */
  1.1228 +  const ModifierKey*
  1.1229 +    GetModifierKeyForDeviceDependentFlags(NSUInteger aFlags) const;
  1.1230 +
  1.1231 +  /**
  1.1232 +   * DispatchKeyEventForFlagsChanged() dispatches keydown event or keyup event
  1.1233 +   * for the aNativeEvent.
  1.1234 +   *
  1.1235 +   * @param aNativeEvent          A native flagschanged event which you want to
  1.1236 +   *                              dispatch our key event for.
  1.1237 +   * @param aDispatchKeyDown      TRUE if you want to dispatch a keydown event.
  1.1238 +   *                              Otherwise, i.e., to dispatch keyup event,
  1.1239 +   *                              FALSE.
  1.1240 +   */
  1.1241 +  void DispatchKeyEventForFlagsChanged(NSEvent* aNativeEvent,
  1.1242 +                                       bool aDispatchKeyDown);
  1.1243 +};
  1.1244 +
  1.1245 +} // namespace widget
  1.1246 +} // namespace mozilla
  1.1247 +
  1.1248 +#endif // TextInputHandler_h_

mercurial