Bug 795230 Use ASCII capable keyboard layout for computing charCode if current input source is an IME mode and open r=smichaud
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 16 Oct 2012 10:43:50 +0900
changeset 110363 a10052ea8e7263e3c9d689e3e98de54964dd5ad9
parent 110362 ce9bde99d93e7fdb3d5dfbc79d374020f99f7af4
child 110364 e676a99a7a8dddc52583c391e0ac0a9d92320d50
push id23680
push useremorley@mozilla.com
push dateTue, 16 Oct 2012 08:09:24 +0000
treeherdermozilla-central@8f145599e4bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmichaud
bugs795230
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 795230 Use ASCII capable keyboard layout for computing charCode if current input source is an IME mode and open r=smichaud
widget/cocoa/TextInputHandler.h
widget/cocoa/TextInputHandler.mm
widget/cocoa/nsBidiKeyboard.mm
widget/cocoa/nsCocoaUtils.h
widget/cocoa/nsCocoaUtils.mm
--- a/widget/cocoa/TextInputHandler.h
+++ b/widget/cocoa/TextInputHandler.h
@@ -47,17 +47,17 @@ enum
  * which is returned by TISCreateInputSourceList.  However, when we release the
  * list, we cannot access the TISInputSourceRef.  So, it's not usable, and it
  * may cause the memory leak bugs.  nsTISInputSource automatically releases the
  * list when the instance is destroyed.
  */
 class TISInputSourceWrapper
 {
 public:
-  static TISInputSourceWrapper& CurrentKeyboardLayout();
+  static TISInputSourceWrapper& CurrentInputSource();
 
   TISInputSourceWrapper()
   {
     mInputSourceList = nullptr;
     Clear();
   }
 
   TISInputSourceWrapper(const char* aID)
@@ -97,23 +97,37 @@ public:
    *                              FALSE.  When TRUE, we use an ANSI keyboard
    *                              instead of the actual keyboard.
    */
   void InitByLayoutID(SInt32 aLayoutID, bool aOverrideKeyboard = false);
   void InitByCurrentInputSource();
   void InitByCurrentKeyboardLayout();
   void InitByCurrentASCIICapableInputSource();
   void InitByCurrentASCIICapableKeyboardLayout();
+  void InitByCurrentInputMethodKeyboardLayoutOverride();
   void InitByTISInputSourceRef(TISInputSourceRef aInputSource);
   void InitByLanguage(CFStringRef aLanguage);
 
+  /**
+   * If the instance is initialized with a keyboard layout input source,
+   * returns it.
+   * If the instance is initialized with an IME mode input source, the result
+   * references the keyboard layout for the IME mode.  However, this can be
+   * initialized only when the IME mode is actually selected.  I.e, if IME mode
+   * input source is initialized with LayoutID or SourceID, this returns null.
+   */
+  TISInputSourceRef GetKeyboardLayoutInputSource() const
+  {
+    return mKeyboardLayout;
+  }
   const UCKeyboardLayout* GetUCKeyboardLayout();
 
   bool IsOpenedIMEMode();
   bool IsIMEMode();
+  bool IsKeyboardLayout();
 
   bool IsASCIICapable()
   {
     NS_ENSURE_TRUE(mInputSource, false);
     return GetBoolProperty(kTISPropertyInputSourceIsASCIICapable);
   }
 
   bool IsEnabled()
@@ -170,17 +184,17 @@ public:
 
   bool GetInputSourceType(nsAString &aType)
   {
     NS_ENSURE_TRUE(mInputSource, false);
     return GetStringProperty(kTISPropertyInputSourceType, aType);
   }
 
   bool IsForRTLLanguage();
-  bool IsInitializedByCurrentKeyboardLayout();
+  bool IsInitializedByCurrentInputSource();
 
   enum {
     // 40 is an actual result of the ::LMGetKbdType() when we connect an
     // unknown keyboard and set the keyboard type to ANSI manually on the
     // set up dialog.
     eKbdType_ANSI = 40
   };
 
@@ -268,16 +282,17 @@ protected:
                          nsKeyEvent& aKeyEvent,
                          UInt32 aKbType);
 
   bool GetBoolProperty(const CFStringRef aKey);
   bool GetStringProperty(const CFStringRef aKey, CFStringRef &aStr);
   bool GetStringProperty(const CFStringRef aKey, nsAString &aStr);
 
   TISInputSourceRef mInputSource;
+  TISInputSourceRef mKeyboardLayout;
   CFArrayRef mInputSourceList;
   const UCKeyboardLayout* mUCKeyboardLayout;
   int8_t mIsRTL;
 
   bool mOverrideKeyboard;
 };
 
 /**
--- a/widget/cocoa/TextInputHandler.mm
+++ b/widget/cocoa/TextInputHandler.mm
@@ -331,62 +331,62 @@ GetWindowLevelName(NSInteger aWindowLeve
     default:
       return "unknown window level";
   }
 }
 
 #endif // #ifdef PR_LOGGING
 
 static uint32_t gHandlerInstanceCount = 0;
-static TISInputSourceWrapper gCurrentKeyboardLayout;
+static TISInputSourceWrapper gCurrentInputSource;
 
 static void
 InitLogModule()
 {
 #ifdef PR_LOGGING
   // Clear() is always called when TISInputSourceWrappper is created.
   if (!gLog) {
     gLog = PR_NewLogModule("TextInputHandlerWidgets");
     TextInputHandler::DebugPrintAllKeyboardLayouts();
     IMEInputHandler::DebugPrintAllIMEModes();
   }
 #endif
 }
 
 static void
-InitCurrentKeyboardLayout()
+InitCurrentInputSource()
 {
   if (gHandlerInstanceCount > 0 &&
-      !gCurrentKeyboardLayout.IsInitializedByCurrentKeyboardLayout()) {
-    gCurrentKeyboardLayout.InitByCurrentKeyboardLayout();
+      !gCurrentInputSource.IsInitializedByCurrentInputSource()) {
+    gCurrentInputSource.InitByCurrentInputSource();
   }
 }
 
 static void
-FinalizeCurrentKeyboardLayout()
+FinalizeCurrentInputSource()
 {
-  gCurrentKeyboardLayout.Clear();
+  gCurrentInputSource.Clear();
 }
 
 
 #pragma mark -
 
 
 /******************************************************************************
  *
  *  TISInputSourceWrapper implementation
  *
  ******************************************************************************/
 
 // static
 TISInputSourceWrapper&
-TISInputSourceWrapper::CurrentKeyboardLayout()
+TISInputSourceWrapper::CurrentInputSource()
 {
-  InitCurrentKeyboardLayout();
-  return gCurrentKeyboardLayout;
+  InitCurrentInputSource();
+  return gCurrentInputSource;
 }
 
 bool
 TISInputSourceWrapper::TranslateToString(UInt32 aKeyCode, UInt32 aModifiers,
                                          UInt32 aKbType, nsAString &aStr)
 {
   aStr.Truncate();
 
@@ -480,16 +480,19 @@ TISInputSourceWrapper::InitByInputSource
   CFDictionaryRef filter =
   ::CFDictionaryCreate(kCFAllocatorDefault, keys, values, 1, NULL, NULL);
   NS_ASSERTION(filter, "failed to create the filter");
   mInputSourceList = ::TISCreateInputSourceList(filter, true);
   ::CFRelease(filter);
   if (::CFArrayGetCount(mInputSourceList) > 0) {
     mInputSource = static_cast<TISInputSourceRef>(
       const_cast<void *>(::CFArrayGetValueAtIndex(mInputSourceList, 0)));
+    if (IsKeyboardLayout()) {
+      mKeyboardLayout = mInputSource;
+    }
   }
 }
 
 void
 TISInputSourceWrapper::InitByLayoutID(SInt32 aLayoutID,
                                       bool aOverrideKeyboard)
 {
   // NOTE: Doument new layout IDs in TextInputHandler.h when you add ones.
@@ -519,62 +522,104 @@ TISInputSourceWrapper::InitByLayoutID(SI
   mOverrideKeyboard = aOverrideKeyboard;
 }
 
 void
 TISInputSourceWrapper::InitByCurrentInputSource()
 {
   Clear();
   mInputSource = ::TISCopyCurrentKeyboardInputSource();
+  mKeyboardLayout = ::TISCopyInputMethodKeyboardLayoutOverride();
+  if (!mKeyboardLayout) {
+    mKeyboardLayout = ::TISCopyCurrentKeyboardLayoutInputSource();
+  }
+  // If this causes composition, the current keyboard layout may input non-ASCII
+  // characters such as Japanese Kana characters or Hangul characters.
+  // However, we need to set ASCII characters to DOM key events for consistency
+  // with other platforms.
+  if (IsOpenedIMEMode()) {
+    TISInputSourceWrapper tis(mKeyboardLayout);
+    if (!tis.IsASCIICapable()) {
+      mKeyboardLayout =
+        ::TISCopyCurrentASCIICapableKeyboardLayoutInputSource();
+    }
+  }
 }
 
 void
 TISInputSourceWrapper::InitByCurrentKeyboardLayout()
 {
   Clear();
   mInputSource = ::TISCopyCurrentKeyboardLayoutInputSource();
+  mKeyboardLayout = mInputSource;
 }
 
 void
 TISInputSourceWrapper::InitByCurrentASCIICapableInputSource()
 {
   Clear();
   mInputSource = ::TISCopyCurrentASCIICapableKeyboardInputSource();
+  mKeyboardLayout = ::TISCopyInputMethodKeyboardLayoutOverride();
+  if (mKeyboardLayout) {
+    TISInputSourceWrapper tis(mKeyboardLayout);
+    if (!tis.IsASCIICapable()) {
+      mKeyboardLayout = nullptr;
+    }
+  }
+  if (!mKeyboardLayout) {
+    mKeyboardLayout =
+      ::TISCopyCurrentASCIICapableKeyboardLayoutInputSource();
+  }
 }
 
 void
 TISInputSourceWrapper::InitByCurrentASCIICapableKeyboardLayout()
 {
   Clear();
   mInputSource = ::TISCopyCurrentASCIICapableKeyboardLayoutInputSource();
+  mKeyboardLayout = mInputSource;
+}
+
+void
+TISInputSourceWrapper::InitByCurrentInputMethodKeyboardLayoutOverride()
+{
+  Clear();
+  mInputSource = ::TISCopyInputMethodKeyboardLayoutOverride();
+  mKeyboardLayout = mInputSource;
 }
 
 void
 TISInputSourceWrapper::InitByTISInputSourceRef(TISInputSourceRef aInputSource)
 {
   Clear();
   mInputSource = aInputSource;
+  if (IsKeyboardLayout()) {
+    mKeyboardLayout = mInputSource;
+  }
 }
 
 void
 TISInputSourceWrapper::InitByLanguage(CFStringRef aLanguage)
 {
   Clear();
   mInputSource = ::TISCopyInputSourceForLanguage(aLanguage);
+  if (IsKeyboardLayout()) {
+    mKeyboardLayout = mInputSource;
+  }
 }
 
 const UCKeyboardLayout*
 TISInputSourceWrapper::GetUCKeyboardLayout()
 {
-  NS_ENSURE_TRUE(mInputSource, nullptr);
+  NS_ENSURE_TRUE(mKeyboardLayout, nullptr);
   if (mUCKeyboardLayout) {
     return mUCKeyboardLayout;
   }
   CFDataRef uchr = static_cast<CFDataRef>(
-    ::TISGetInputSourceProperty(mInputSource,
+    ::TISGetInputSourceProperty(mKeyboardLayout,
                                 kTISPropertyUnicodeKeyLayoutData));
 
   // We should be always able to get the layout here.
   NS_ENSURE_TRUE(uchr, nullptr);
   mUCKeyboardLayout =
     reinterpret_cast<const UCKeyboardLayout*>(CFDataGetBytePtr(uchr));
   return mUCKeyboardLayout;
 }
@@ -622,16 +667,27 @@ TISInputSourceWrapper::IsIMEMode()
   CFStringRef str;
   GetInputSourceType(str);
   NS_ENSURE_TRUE(str, false);
   return ::CFStringCompare(kTISTypeKeyboardInputMode,
                            str, 0) == kCFCompareEqualTo;
 }
 
 bool
+TISInputSourceWrapper::IsKeyboardLayout()
+{
+  NS_ENSURE_TRUE(mInputSource, false);
+  CFStringRef str;
+  GetInputSourceType(str);
+  NS_ENSURE_TRUE(str, false);
+  return ::CFStringCompare(kTISTypeKeyboardLayout,
+                           str, 0) == kCFCompareEqualTo;
+}
+
+bool
 TISInputSourceWrapper::GetLanguageList(CFArrayRef &aLanguageList)
 {
   NS_ENSURE_TRUE(mInputSource, false);
   aLanguageList = static_cast<CFArrayRef>(
     ::TISGetInputSourceProperty(mInputSource,
                                 kTISPropertyInputSourceLanguages));
   return aLanguageList != nullptr;
 }
@@ -670,19 +726,19 @@ TISInputSourceWrapper::IsForRTLLanguage(
     NS_ENSURE_TRUE(ret, ret);
     PRUnichar ch = str.IsEmpty() ? PRUnichar(0) : str.CharAt(0);
     mIsRTL = UCS2_CHAR_IS_BIDI(ch) || ch == 0xD802 || ch == 0xD803;
   }
   return mIsRTL != 0;
 }
 
 bool
-TISInputSourceWrapper::IsInitializedByCurrentKeyboardLayout()
+TISInputSourceWrapper::IsInitializedByCurrentInputSource()
 {
-  return mInputSource == ::TISCopyCurrentKeyboardLayoutInputSource();
+  return mInputSource == ::TISCopyCurrentKeyboardInputSource();
 }
 
 void
 TISInputSourceWrapper::Select()
 {
   if (!mInputSource)
     return;
   ::TISSelectInputSource(mInputSource);
@@ -694,16 +750,17 @@ TISInputSourceWrapper::Clear()
   // Clear() is always called when TISInputSourceWrappper is created.
   InitLogModule();
 
   if (mInputSourceList) {
     ::CFRelease(mInputSourceList);
   }
   mInputSourceList = nullptr;
   mInputSource = nullptr;
+  mKeyboardLayout = nullptr;
   mIsRTL = -1;
   mUCKeyboardLayout = nullptr;
   mOverrideKeyboard = false;
 }
 
 void
 TISInputSourceWrapper::InitKeyEvent(NSEvent *aNativeKeyEvent,
                                     nsKeyEvent& aKeyEvent,
@@ -741,23 +798,39 @@ TISInputSourceWrapper::InitKeyEvent(NSEv
 
   // Decide what string will be input.
   nsAutoString insertString;
   if (aInsertString) {
     // If the caller expects that the aInsertString will be input, we shouldn't
     // change it.
     insertString = *aInsertString;
   } else if (isPrintableKey) {
-    // If the caller isn't sure what string will be input, let's use characters
-    // of NSEvent.
-    // XXX This is wrong at Hiragana or Katakana with Kana-Nyuryoku mode or
-    //     Chinese or Koran IME modes.  We should use ASCII characters at that
-    //     time.
-    nsCocoaUtils::GetStringForNSString([aNativeKeyEvent characters],
-                                       insertString);
+    // If IME is open, [aNativeKeyEvent characters] may be a character
+    // which will be appended to the composition string.  However, especially,
+    // while IME is disabled, most users and developers expect the key event
+    // works as IME closed.  So, we should compute the insertString with
+    // the ASCII capable keyboard layout.
+    // NOTE: Such keyboard layouts typically change the layout to its ASCII
+    //       capable layout when Command key is pressed.  And we don't worry
+    //       when Control key is pressed too because it causes inputting
+    //       control characters.
+    if (!aKeyEvent.IsMeta() && !aKeyEvent.IsControl() && IsOpenedIMEMode()) {
+      UInt32 state =
+        nsCocoaUtils::ConvertToCarbonModifier([aNativeKeyEvent modifierFlags]);
+      PRUint32 ch = TranslateToChar(nativeKeyCode, state, kbType);
+      if (ch) {
+        insertString = ch;
+      }
+    } else {
+      // If the caller isn't sure what string will be input, let's use
+      // characters of NSEvent.
+      nsCocoaUtils::GetStringForNSString([aNativeKeyEvent characters],
+                                         insertString);
+    }
+
     // If control key is pressed and the eventChars is a non-printable control
     // character, we should convert it to ASCII alphabet.
     if (aKeyEvent.IsControl() &&
         !insertString.IsEmpty() && insertString[0] <= PRUnichar(26)) {
       insertString = (aKeyEvent.IsShift() ^ aKeyEvent.IsCapsLocked()) ?
         static_cast<PRUnichar>(insertString[0] + ('A' - 1)) :
         static_cast<PRUnichar>(insertString[0] + ('a' - 1));
     }
@@ -872,17 +945,17 @@ TISInputSourceWrapper::InitKeyEvent(NSEv
 
 void
 TISInputSourceWrapper::InitKeyPressEvent(NSEvent *aNativeKeyEvent,
                                          PRUnichar aInsertChar,
                                          nsKeyEvent& aKeyEvent,
                                          UInt32 aKbType)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
-  
+
   NS_ASSERTION(aKeyEvent.message == NS_KEY_PRESS,
                "aKeyEvent must be NS_KEY_PRESS event");
 
 #ifdef PR_LOGGING
   if (PR_LOG_TEST(gLog, PR_LOG_ALWAYS)) {
     nsAutoString chars;
     nsCocoaUtils::GetStringForNSString([aNativeKeyEvent characters], chars);
     NS_ConvertUTF16toUTF8 utf8Chars(chars);
@@ -1251,17 +1324,18 @@ TextInputHandler::DebugPrintAllKeyboardL
       nsAutoString name, isid;
       tis.GetLocalizedName(name);
       tis.GetInputSourceID(isid);
       PR_LOG(gLog, PR_LOG_ALWAYS,
              ("  %s\t<%s>%s%s\n",
               NS_ConvertUTF16toUTF8(name).get(),
               NS_ConvertUTF16toUTF8(isid).get(),
               tis.IsASCIICapable() ? "" : "\t(Isn't ASCII capable)",
-              tis.GetUCKeyboardLayout() ? "" : "\t(uchr is NOT AVAILABLE)"));
+              tis.IsKeyboardLayout() && tis.GetUCKeyboardLayout() ?
+                "" : "\t(uchr is NOT AVAILABLE)"));
     }
     ::CFRelease(list);
   }
 #endif // #ifdef PR_LOGGING
 }
 
 
 #pragma mark -
@@ -1751,42 +1825,51 @@ IMEInputHandler::OnCurrentTextInputSourc
 
 #ifdef PR_LOGGING
   if (PR_LOG_TEST(gLog, PR_LOG_ALWAYS)) {
     static CFStringRef sLastTIS = nullptr;
     CFStringRef newTIS;
     tis.GetInputSourceID(newTIS);
     if (!sLastTIS ||
         ::CFStringCompare(sLastTIS, newTIS, 0) != kCFCompareEqualTo) {
-      TISInputSourceWrapper tis1, tis2, tis3;
+      TISInputSourceWrapper tis1, tis2, tis3, tis4, tis5;
       tis1.InitByCurrentKeyboardLayout();
       tis2.InitByCurrentASCIICapableInputSource();
       tis3.InitByCurrentASCIICapableKeyboardLayout();
-      CFStringRef is0, is1, is2, is3, type0, lang0, bundleID0;
+      tis4.InitByCurrentInputMethodKeyboardLayoutOverride();
+      tis5.InitByTISInputSourceRef(tis.GetKeyboardLayoutInputSource());
+      CFStringRef is0 = nullptr, is1 = nullptr, is2 = nullptr, is3 = nullptr,
+                  is4 = nullptr, is5 = nullptr, type0 = nullptr,
+                  lang0 = nullptr, bundleID0 = nullptr;
       tis.GetInputSourceID(is0);
       tis1.GetInputSourceID(is1);
       tis2.GetInputSourceID(is2);
       tis3.GetInputSourceID(is3);
+      tis4.GetInputSourceID(is4);
+      tis5.GetInputSourceID(is5);
       tis.GetInputSourceType(type0);
       tis.GetPrimaryLanguage(lang0);
       tis.GetBundleID(bundleID0);
 
       PR_LOG(gLog, PR_LOG_ALWAYS,
         ("IMEInputHandler::OnCurrentTextInputSourceChange,\n"
          "  Current Input Source is changed to:\n"
          "    currentInputManager=%p\n"
          "    %s\n"
          "      type=%s %s\n"
+         "      overridden keyboard layout=%s\n"
+         "      used keyboard layout for translation=%s\n"
          "    primary language=%s\n"
          "    bundle ID=%s\n"
          "    current ASCII capable Input Source=%s\n"
          "    current Keyboard Layout=%s\n"
          "    current ASCII capable Keyboard Layout=%s",
          [NSInputManager currentInputManager], GetCharacters(is0),
          GetCharacters(type0), tis.IsASCIICapable() ? "- ASCII capable " : "",
+         GetCharacters(is4), GetCharacters(is5),
          GetCharacters(lang0), GetCharacters(bundleID0),
          GetCharacters(is2), GetCharacters(is1), GetCharacters(is3)));
     }
     sLastTIS = newTIS;
   }
 #endif // #ifdef PR_LOGGING
 }
 
@@ -3256,33 +3339,33 @@ PluginTextInputHandler::HandleCarbonPlug
   }
 
   UInt32 macKeyCode;
   status = ::GetEventParameter(aKeyEvent, kEventParamKeyCode,
                                typeUInt32, NULL, sizeof(macKeyCode), NULL,
                                &macKeyCode);
   NS_ENSURE_TRUE(status == noErr, );
 
-  TISInputSourceWrapper currentKeyboardLayout;
-  currentKeyboardLayout.InitByCurrentKeyboardLayout();
+  TISInputSourceWrapper& currentInputSource =
+    TISInputSourceWrapper::CurrentInputSource();
 
   EventRef cloneEvent = ::CopyEvent(aKeyEvent);
   for (uint32_t i = 0; i < numCharCodes; ++i) {
     status = ::SetEventParameter(cloneEvent, kEventParamKeyMacCharCodes,
                                  typeChar, 1, charCodes.Elements() + i);
     NS_ENSURE_TRUE(status == noErr, );
 
     EventRecord eventRec;
     if (::ConvertEventRefToEventRecord(cloneEvent, &eventRec)) {
       nsKeyEvent keydownEvent(true, NS_KEY_DOWN, mWidget);
       nsCocoaUtils::InitInputEvent(keydownEvent, cocoaModifiers);
 
       uint32_t keyCode =
-        currentKeyboardLayout.ComputeGeckoKeyCode(macKeyCode, ::LMGetKbdType(),
-                                                  keydownEvent.IsMeta());
+        currentInputSource.ComputeGeckoKeyCode(macKeyCode, ::LMGetKbdType(),
+                                               keydownEvent.IsMeta());
       uint32_t charCode(charCodes.ElementAt(i));
 
       keydownEvent.time = PR_IntervalNow();
       keydownEvent.pluginEvent = &eventRec;
       if (IsSpecialGeckoKey(macKeyCode)) {
         keydownEvent.keyCode = keyCode;
       } else {
         // XXX This is wrong. charCode must be 0 for keydown event.
@@ -3622,17 +3705,17 @@ TextInputHandlerBase::TextInputHandlerBa
   gHandlerInstanceCount++;
   mView = [aNativeView retain];
 }
 
 TextInputHandlerBase::~TextInputHandlerBase()
 {
   [mView release];
   if (--gHandlerInstanceCount == 0) {
-    FinalizeCurrentKeyboardLayout();
+    FinalizeCurrentInputSource();
   }
 }
 
 bool
 TextInputHandlerBase::OnDestroyWidget(nsChildView* aDestroyingWidget)
 {
   PR_LOG(gLog, PR_LOG_ALWAYS,
     ("%p TextInputHandlerBase::OnDestroyWidget, "
@@ -3663,23 +3746,24 @@ TextInputHandlerBase::DispatchEvent(nsGU
 
 void
 TextInputHandlerBase::InitKeyEvent(NSEvent *aNativeKeyEvent,
                                    nsKeyEvent& aKeyEvent,
                                    const nsAString* aInsertString)
 {
   NS_ASSERTION(aNativeKeyEvent, "aNativeKeyEvent must not be NULL");
 
-  TISInputSourceWrapper tis;
   if (mKeyboardOverride.mOverrideEnabled) {
+    TISInputSourceWrapper tis;
     tis.InitByLayoutID(mKeyboardOverride.mKeyboardLayout, true);
-  } else {
-    tis.InitByCurrentKeyboardLayout();
+    tis.InitKeyEvent(aNativeKeyEvent, aKeyEvent, aInsertString);
+    return;
   }
-  tis.InitKeyEvent(aNativeKeyEvent, aKeyEvent, aInsertString);
+  TISInputSourceWrapper::CurrentInputSource().
+    InitKeyEvent(aNativeKeyEvent, aKeyEvent, aInsertString);
 }
 
 nsresult
 TextInputHandlerBase::SynthesizeNativeKeyEvent(
                         int32_t aNativeKeyboardLayout,
                         int32_t aNativeKeyCode,
                         uint32_t aModifierFlags,
                         const nsAString& aCharacters,
--- a/widget/cocoa/nsBidiKeyboard.mm
+++ b/widget/cocoa/nsBidiKeyboard.mm
@@ -18,17 +18,17 @@ nsBidiKeyboard::nsBidiKeyboard() : nsIBi
 }
 
 nsBidiKeyboard::~nsBidiKeyboard()
 {
 }
 
 NS_IMETHODIMP nsBidiKeyboard::IsLangRTL(bool *aIsRTL)
 {
-  *aIsRTL = TISInputSourceWrapper::CurrentKeyboardLayout().IsForRTLLanguage();
+  *aIsRTL = TISInputSourceWrapper::CurrentInputSource().IsForRTLLanguage();
   return NS_OK;
 }
 
 NS_IMETHODIMP nsBidiKeyboard::SetLangFromBidiLevel(uint8_t aLevel)
 {
   // XXX Insert platform specific code to set keyboard language
   return NS_OK;
 }
--- a/widget/cocoa/nsCocoaUtils.h
+++ b/widget/cocoa/nsCocoaUtils.h
@@ -273,15 +273,22 @@ class nsCocoaUtils
                              NSUInteger aModifiers);
 
   /**
    * GetCurrentModifiers() returns Cocoa modifier flags for current state.
    */
   static NSUInteger GetCurrentModifiers();
 
   /**
+   * ConvertToCarbonModifier() returns carbon modifier flags for the cocoa
+   * modifier flags.
+   * NOTE: The result never includes right*Key.
+   */
+  static UInt32 ConvertToCarbonModifier(NSUInteger aCocoaModifier);
+
+  /**
    * Whether to support HiDPI rendering. For testing purposes, to be removed
    * once we're comfortable with the HiDPI behavior.
    */
   static bool HiDPIEnabled();
 };
 
 #endif // nsCocoaUtils_h_
--- a/widget/cocoa/nsCocoaUtils.mm
+++ b/widget/cocoa/nsCocoaUtils.mm
@@ -516,16 +516,45 @@ nsCocoaUtils::GetCurrentModifiers()
   }
   if (carbonModifiers & cmdKey) {
     cocoaModifiers |= NSCommandKeyMask;
   }
 
   return cocoaModifiers;
 }
 
+// static
+UInt32
+nsCocoaUtils::ConvertToCarbonModifier(NSUInteger aCocoaModifier)
+{
+  UInt32 carbonModifier = 0;
+  if (aCocoaModifier & NSAlphaShiftKeyMask) {
+    carbonModifier |= alphaLock;
+  }
+  if (aCocoaModifier & NSControlKeyMask) {
+    carbonModifier |= controlKey;
+  }
+  if (aCocoaModifier & NSAlternateKeyMask) {
+    carbonModifier |= optionKey;
+  }
+  if (aCocoaModifier & NSShiftKeyMask) {
+    carbonModifier |= shiftKey;
+  }
+  if (aCocoaModifier & NSCommandKeyMask) {
+    carbonModifier |= cmdKey;
+  }
+  if (aCocoaModifier & NSNumericPadKeyMask) {
+    carbonModifier |= kEventKeyModifierNumLockMask;
+  }
+  if (aCocoaModifier & NSFunctionKeyMask) {
+    carbonModifier |= kEventKeyModifierFnMask;
+  }
+  return carbonModifier;
+}
+
 // While HiDPI support is not 100% complete and tested, we'll have a pref
 // to allow it to be turned off in case of problems (or for testing purposes).
 
 // gfx.hidpi.enabled is an integer with the meaning:
 //    <= 0 : HiDPI support is disabled
 //       1 : HiDPI enabled provided all screens have the same backing resolution
 //     > 1 : HiDPI enabled even if there are a mixture of screen modes