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 110495 a10052ea8e7263e3c9d689e3e98de54964dd5ad9
parent 110494 ce9bde99d93e7fdb3d5dfbc79d374020f99f7af4
child 110496 e676a99a7a8dddc52583c391e0ac0a9d92320d50
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewerssmichaud
bugs795230
milestone19.0a1
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