Merge mozilla-central to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 18 Dec 2013 13:03:15 +0100
changeset 161083 ac1f669afa6f5a48983ea1702a25421458f493bd
parent 161082 b7d469a149e9988adcfbb35acad9e0b757a04ee1 (current diff)
parent 161020 60373454fc522b65124da073ae9204799c2db9f9 (diff)
child 161084 2e8fb54ac9ff0e95556e97d42f28df19ea88600f
push id25867
push userryanvm@gmail.com
push dateThu, 19 Dec 2013 02:19:33 +0000
treeherdermozilla-central@04a70c8908de [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone29.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
Merge mozilla-central to fx-team
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "2cc6e0988688b33fa46e3a05a726fb7919d7420e", 
+    "revision": "7412c36923b59f6e4d7076de5be7e6ded6ddc586", 
     "repo_path": "/integration/gaia-central"
 }
--- a/browser/metro/base/tests/mochitest/head.js
+++ b/browser/metro/base/tests/mochitest/head.js
@@ -556,33 +556,16 @@ function waitForObserver(aObsEvent, aTim
   }
 }
 
 /*=============================================================================
  * Native input helpers - these helpers send input directly to the os
  * generating os level input events that get processed by widget and
  * apzc logic.
  *===========================================================================*/
-
-// Keyboard layouts for use with synthesizeNativeKey
-const usEnglish = 0x409;
-const arSpanish = 0x2C0A;
-
-// Modifiers for use with synthesizeNativeKey
-const leftShift = 0x100;
-const rightShift = 0x200;
-const leftControl = 0x400;
-const rightControl = 0x800;
-const leftAlt = 0x1000;
-const rightAlt = 0x2000;
-
-function synthesizeNativeKey(aKbLayout, aVKey, aModifiers) {
-  Browser.windowUtils.sendNativeKeyEvent(aKbLayout, aVKey, aModifiers, '', '');
-}
-
 function synthesizeNativeMouse(aElement, aOffsetX, aOffsetY, aMsg) {
   let x = aOffsetX;
   let y = aOffsetY;
   if (aElement) {
     if (aElement.getBoundingClientRect) {
       let rect = aElement.getBoundingClientRect();
       x += rect.left;
       y += rect.top;
--- a/configure.in
+++ b/configure.in
@@ -3909,16 +3909,17 @@ MOZ_NATIVE_ICU=
 MOZ_ARG_WITH_BOOL(system-icu,
 [  --with-system-icu
                           Use system ICU (located with pkgconfig)],
     MOZ_NATIVE_ICU=1)
 
 if test -n "$MOZ_NATIVE_ICU"; then
     PKG_CHECK_MODULES(MOZ_ICU, icu-i18n >= 50.1)
     MOZ_JS_STATIC_LIBS="$MOZ_JS_STATIC_LIBS $MOZ_ICU_LIBS"
+    MOZ_SHARED_ICU=1
 fi
 
 AC_SUBST(MOZ_NATIVE_ICU)
 
 dnl ========================================================
 dnl Java SDK support
 dnl ========================================================
 
--- a/content/events/src/nsContentEventHandler.cpp
+++ b/content/events/src/nsContentEventHandler.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 sw=2 et tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsContentEventHandler.h"
 #include "nsCOMPtr.h"
+#include "nsFocusManager.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsISelection.h"
 #include "nsIDOMRange.h"
 #include "nsRange.h"
 #include "nsCaret.h"
 #include "nsCopySupport.h"
 #include "nsFrameSelection.h"
@@ -26,16 +27,17 @@
 #include "nsIMEStateManager.h"
 #include "nsIObjectFrame.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/TextEvents.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::dom;
+using namespace mozilla::widget;
 
 /******************************************************************/
 /* nsContentEventHandler                                          */
 /******************************************************************/
 
 nsContentEventHandler::nsContentEventHandler(
                               nsPresContext* aPresContext) :
   mPresContext(aPresContext),
@@ -122,16 +124,65 @@ nsContentEventHandler::Init(WidgetSelect
   nsresult rv = InitCommon();
   NS_ENSURE_SUCCESS(rv, rv);
 
   aEvent->mSucceeded = false;
 
   return NS_OK;
 }
 
+nsIContent*
+nsContentEventHandler::GetFocusedContent()
+{
+  nsIDocument* doc = mPresShell->GetDocument();
+  if (!doc) {
+    return nullptr;
+  }
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(doc->GetWindow());
+  nsCOMPtr<nsPIDOMWindow> focusedWindow;
+  return nsFocusManager::GetFocusedDescendant(window, true,
+                                              getter_AddRefs(focusedWindow));
+}
+
+bool
+nsContentEventHandler::IsPlugin(nsIContent* aContent)
+{
+  return aContent &&
+         aContent->GetDesiredIMEState().mEnabled == IMEState::PLUGIN;
+}
+
+nsresult
+nsContentEventHandler::QueryContentRect(nsIContent* aContent,
+                                        WidgetQueryContentEvent* aEvent)
+{
+  NS_PRECONDITION(aContent, "aContent must not be null");
+
+  nsIFrame* frame = aContent->GetPrimaryFrame();
+  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
+
+  // get rect for first frame
+  nsRect resultRect(nsPoint(0, 0), frame->GetRect().Size());
+  nsresult rv = ConvertToRootViewRelativeOffset(frame, resultRect);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // account for any additional frames
+  while ((frame = frame->GetNextContinuation()) != nullptr) {
+    nsRect frameRect(nsPoint(0, 0), frame->GetRect().Size());
+    rv = ConvertToRootViewRelativeOffset(frame, frameRect);
+    NS_ENSURE_SUCCESS(rv, rv);
+    resultRect.UnionRect(resultRect, frameRect);
+  }
+
+  aEvent->mReply.mRect =
+      resultRect.ToOutsidePixels(mPresContext->AppUnitsPerDevPixel());
+  aEvent->mSucceeded = true;
+
+  return NS_OK;
+}
+
 // Editor places a bogus BR node under its root content if the editor doesn't
 // have any text. This happens even for single line editors.
 // When we get text content and when we change the selection,
 // we don't want to include the bogus BRs at the end.
 static bool IsContentBR(nsIContent* aContent)
 {
   return aContent->IsHTML() &&
          aContent->Tag() == nsGkAtoms::br &&
@@ -671,35 +722,20 @@ nsContentEventHandler::OnQueryTextRect(W
 
 nsresult
 nsContentEventHandler::OnQueryEditorRect(WidgetQueryContentEvent* aEvent)
 {
   nsresult rv = Init(aEvent);
   if (NS_FAILED(rv))
     return rv;
 
-  nsIFrame* frame = mRootContent->GetPrimaryFrame();
-  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
-
-  // get rect for first frame
-  nsRect resultRect(nsPoint(0, 0), frame->GetRect().Size());
-  rv = ConvertToRootViewRelativeOffset(frame, resultRect);
+  nsIContent* focusedContent = GetFocusedContent();
+  rv = QueryContentRect(IsPlugin(focusedContent) ?
+                          focusedContent : mRootContent.get(), aEvent);
   NS_ENSURE_SUCCESS(rv, rv);
-
-  // account for any additional frames
-  while ((frame = frame->GetNextContinuation()) != nullptr) {
-    nsRect frameRect(nsPoint(0, 0), frame->GetRect().Size());
-    rv = ConvertToRootViewRelativeOffset(frame, frameRect);
-    NS_ENSURE_SUCCESS(rv, rv);
-    resultRect.UnionRect(resultRect, frameRect);
-  }
-
-  aEvent->mReply.mRect =
-      resultRect.ToOutsidePixels(mPresContext->AppUnitsPerDevPixel());
-  aEvent->mSucceeded = true;
   return NS_OK;
 }
 
 nsresult
 nsContentEventHandler::OnQueryCaretRect(WidgetQueryContentEvent* aEvent)
 {
   nsresult rv = Init(aEvent);
   if (NS_FAILED(rv))
--- a/content/events/src/nsContentEventHandler.h
+++ b/content/events/src/nsContentEventHandler.h
@@ -76,16 +76,23 @@ public:
                                            uint32_t* aOffset);
   static nsresult GetFlatTextOffsetOfRange(nsIContent* aRootContent,
                                            nsRange* aRange,
                                            uint32_t* aOffset);
   // Get the native text length of a content node excluding any children
   static uint32_t GetNativeTextLength(nsIContent* aContent,
                                       uint32_t aMaxLength = UINT32_MAX);
 protected:
+  // Returns focused content (including its descendant documents).
+  nsIContent* GetFocusedContent();
+  // Returns true if the content is a plugin host.
+  bool IsPlugin(nsIContent* aContent);
+  // QueryContentRect() sets the rect of aContent's frame(s) to aEvent.
+  nsresult QueryContentRect(nsIContent* aContent,
+                            mozilla::WidgetQueryContentEvent* aEvent);
   // Make the DOM range from the offset of FlatText and the text length.
   // If aExpandToClusterBoundaries is true, the start offset and the end one are
   // expanded to nearest cluster boundaries.
   nsresult SetRangeFromFlatTextOffset(nsRange* aRange,
                                       uint32_t aNativeOffset,
                                       uint32_t aNativeLength,
                                       bool aExpandToClusterBoundaries,
                                       uint32_t* aNewNativeOffset = nullptr);
--- a/content/media/MediaDecoder.cpp
+++ b/content/media/MediaDecoder.cpp
@@ -8,26 +8,26 @@
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/MathAlgorithms.h"
 #include <limits>
 #include "nsIObserver.h"
 #include "nsTArray.h"
 #include "VideoUtils.h"
 #include "MediaDecoderStateMachine.h"
 #include "mozilla/dom/TimeRanges.h"
-#include "nsContentUtils.h"
 #include "ImageContainer.h"
 #include "MediaResource.h"
 #include "nsError.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/StaticPtr.h"
 #include "nsIMemoryReporter.h"
 #include "nsComponentManagerUtils.h"
 #include "nsITimer.h"
 #include <algorithm>
+#include "MediaShutdownManager.h"
 
 #ifdef MOZ_WMF
 #include "WMFDecoder.h"
 #endif
 
 using namespace mozilla::layers;
 using namespace mozilla::dom;
 
@@ -439,17 +439,17 @@ MediaDecoder::MediaDecoder() :
 #endif
 }
 
 bool MediaDecoder::Init(MediaDecoderOwner* aOwner)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mOwner = aOwner;
   mVideoFrameContainer = aOwner->GetVideoFrameContainer();
-  nsContentUtils::RegisterShutdownObserver(this);
+  MediaShutdownManager::Instance().Register(this);
   return true;
 }
 
 void MediaDecoder::Shutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mShuttingDown)
@@ -475,17 +475,17 @@ void MediaDecoder::Shutdown()
     mResource->Close();
   }
 
   ChangeState(PLAY_STATE_SHUTDOWN);
 
   StopProgress();
   mOwner = nullptr;
 
-  nsContentUtils::UnregisterShutdownObserver(this);
+  MediaShutdownManager::Instance().Unregister(this);
 }
 
 MediaDecoder::~MediaDecoder()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MediaMemoryTracker::RemoveMediaDecoder(this);
   UnpinForSeek();
   MOZ_COUNT_DTOR(MediaDecoder);
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -21,16 +21,18 @@
 #include "VideoUtils.h"
 #include "mozilla/dom/TimeRanges.h"
 #include "nsDeque.h"
 #include "AudioSegment.h"
 #include "VideoSegment.h"
 #include "ImageContainer.h"
 #include "nsComponentManagerUtils.h"
 #include "nsITimer.h"
+#include "nsContentUtils.h"
+#include "MediaShutdownManager.h"
 
 #include "prenv.h"
 #include "mozilla/Preferences.h"
 #include <algorithm>
 
 namespace mozilla {
 
 using namespace mozilla::layers;
@@ -173,17 +175,17 @@ public:
   // Call on main thread only.
   void CleanupGlobalStateMachine();
 
   // Return the global state machine thread. Call from any thread.
   nsIThread* GetGlobalStateMachineThread()
   {
     ReentrantMonitorAutoEnter mon(mMonitor);
     NS_ASSERTION(mStateMachineThread, "Should have non-null state machine thread!");
-    return mStateMachineThread;
+    return mStateMachineThread->GetThread();
   }
 
   // Requests that a decode thread be created for aStateMachine. The thread
   // may be created immediately, or after some delay, once a thread becomes
   // available. The request can be cancelled using CancelCreateDecodeThread().
   // It's the callers responsibility to not call this more than once for any
   // given state machine.
   nsresult RequestCreateDecodeThread(MediaDecoderStateMachine* aStateMachine);
@@ -229,17 +231,17 @@ private:
   // Number of instances of decoder threads that are
   // currently instantiated. Access only with the
   // mMonitor lock held. Can be used from any thread.
   uint32_t mDecodeThreadCount;
 
   // Global state machine thread. Write on the main thread
   // only, read from the decoder threads. Synchronized via
   // the mMonitor.
-  nsIThread* mStateMachineThread;
+  nsRefPtr<StateMachineThread> mStateMachineThread;
 
   // Queue of state machines waiting for decode threads. Entries at the front
   // get their threads first.
   nsDeque mPending;
 };
 
 StateMachineTracker* StateMachineTracker::sInstance = nullptr;
 
@@ -253,17 +255,18 @@ StateMachineTracker& StateMachineTracker
 }
 
 void StateMachineTracker::EnsureGlobalStateMachine()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   ReentrantMonitorAutoEnter mon(mMonitor);
   if (mStateMachineCount == 0) {
     NS_ASSERTION(!mStateMachineThread, "Should have null state machine thread!");
-    DebugOnly<nsresult> rv = NS_NewNamedThread("Media State", &mStateMachineThread);
+    mStateMachineThread = new StateMachineThread();
+    DebugOnly<nsresult> rv = mStateMachineThread->Init();
     NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Can't create media state machine thread");
   }
   mStateMachineCount++;
 }
 
 #ifdef DEBUG
 bool StateMachineTracker::IsQueued(MediaDecoderStateMachine* aStateMachine)
 {
@@ -286,21 +289,18 @@ void StateMachineTracker::CleanupGlobalS
   NS_ABORT_IF_FALSE(mStateMachineCount > 0,
     "State machine ref count must be > 0");
   mStateMachineCount--;
   if (mStateMachineCount == 0) {
     DECODER_LOG(PR_LOG_DEBUG, ("Destroying media state machine thread"));
     NS_ASSERTION(mPending.GetSize() == 0, "Shouldn't all requests be handled by now?");
     {
       ReentrantMonitorAutoEnter mon(mMonitor);
-      nsCOMPtr<nsIRunnable> event = new ShutdownThreadEvent(mStateMachineThread);
-      NS_RELEASE(mStateMachineThread);
+      mStateMachineThread->Shutdown();
       mStateMachineThread = nullptr;
-      NS_DispatchToMainThread(event);
-
       NS_ASSERTION(mDecodeThreadCount == 0, "Decode thread count must be zero.");
       sInstance = nullptr;
     }
     delete this;
   }
 }
 
 void StateMachineTracker::NoteDecodeThreadDestroyed()
new file mode 100644
--- /dev/null
+++ b/content/media/MediaShutdownManager.cpp
@@ -0,0 +1,238 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "MediaShutdownManager.h"
+#include "nsContentUtils.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "MediaDecoder.h"
+
+namespace mozilla {
+
+StateMachineThread::StateMachineThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_COUNT_CTOR(StateMachineThread);
+}
+
+StateMachineThread::~StateMachineThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_COUNT_DTOR(StateMachineThread);
+}
+
+void
+StateMachineThread::Shutdown()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mThread);
+  if (mThread) {
+    nsCOMPtr<nsIRunnable> event =
+      NS_NewRunnableMethod(this, &StateMachineThread::ShutdownThread);
+    NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
+  }
+}
+
+void
+StateMachineThread::ShutdownThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mThread);
+  mThread->Shutdown();
+  mThread = nullptr;
+  MediaShutdownManager::Instance().Unregister(this);
+}
+
+nsresult
+StateMachineThread::Init()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  nsresult rv = NS_NewNamedThread("Media State", getter_AddRefs(mThread));
+  NS_ENSURE_SUCCESS(rv, rv);
+  MediaShutdownManager::Instance().Register(this);
+  return NS_OK;
+}
+
+nsIThread*
+StateMachineThread::GetThread()
+{
+  MOZ_ASSERT(mThread);
+  return mThread;
+}
+
+void
+StateMachineThread::SpinUntilShutdownComplete()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  while (mThread) {
+    bool processed = false;
+    nsresult rv = NS_GetCurrentThread()->ProcessNextEvent(true, &processed);
+    if (NS_FAILED(rv)) {
+      NS_WARNING("Failed to spin main thread while awaiting media shutdown");
+      break;
+    }
+  }
+}
+
+NS_IMPL_ISUPPORTS1(MediaShutdownManager, nsIObserver)
+
+MediaShutdownManager::MediaShutdownManager()
+  : mIsObservingShutdown(false),
+    mIsDoingXPCOMShutDown(false)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_COUNT_CTOR(MediaShutdownManager);
+}
+
+MediaShutdownManager::~MediaShutdownManager()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_COUNT_DTOR(MediaShutdownManager);
+}
+
+// Note that we don't use ClearOnShutdown() on this StaticRefPtr, as that
+// may interfere with our shutdown listener.
+StaticRefPtr<MediaShutdownManager> MediaShutdownManager::sInstance;
+
+MediaShutdownManager&
+MediaShutdownManager::Instance()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!sInstance) {
+    sInstance = new MediaShutdownManager();
+  }
+  return *sInstance;
+}
+
+void
+MediaShutdownManager::EnsureCorrectShutdownObserverState()
+{
+  MOZ_ASSERT(!mIsDoingXPCOMShutDown);
+  bool needShutdownObserver = (mDecoders.Count() > 0) ||
+                              (mStateMachineThreads.Count() > 0);
+  if (needShutdownObserver != mIsObservingShutdown) {
+    mIsObservingShutdown = needShutdownObserver;
+    if (mIsObservingShutdown) {
+      nsContentUtils::RegisterShutdownObserver(this);
+    } else {
+      nsContentUtils::UnregisterShutdownObserver(this);
+      // Clear our singleton reference. This will probably delete
+      // this instance, so don't deref |this| clearing sInstance.
+      sInstance = nullptr;
+    }
+  }
+}
+
+void
+MediaShutdownManager::Register(MediaDecoder* aDecoder)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  // Don't call Register() after you've Unregistered() all the decoders,
+  // that's not going to work.
+  MOZ_ASSERT(!mDecoders.Contains(aDecoder));
+  mDecoders.PutEntry(aDecoder);
+  MOZ_ASSERT(mDecoders.Contains(aDecoder));
+  MOZ_ASSERT(mDecoders.Count() > 0);
+  EnsureCorrectShutdownObserverState();
+}
+
+void
+MediaShutdownManager::Unregister(MediaDecoder* aDecoder)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mDecoders.Contains(aDecoder));
+  if (!mIsDoingXPCOMShutDown) {
+    mDecoders.RemoveEntry(aDecoder);
+    EnsureCorrectShutdownObserverState();
+  }
+}
+
+NS_IMETHODIMP
+MediaShutdownManager::Observe(nsISupports *aSubjet,
+                              const char *aTopic,
+                              const PRUnichar *someData)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
+    Shutdown();
+  }
+  return NS_OK;
+}
+
+void
+MediaShutdownManager::Register(StateMachineThread* aThread)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!mStateMachineThreads.Contains(aThread));
+  mStateMachineThreads.PutEntry(aThread);
+  MOZ_ASSERT(mStateMachineThreads.Contains(aThread));
+  MOZ_ASSERT(mStateMachineThreads.Count() > 0);
+  EnsureCorrectShutdownObserverState();
+}
+
+void
+MediaShutdownManager::Unregister(StateMachineThread* aThread)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mStateMachineThreads.Contains(aThread));
+  if (!mIsDoingXPCOMShutDown) {
+    mStateMachineThreads.RemoveEntry(aThread);
+    EnsureCorrectShutdownObserverState();
+  }
+}
+
+static PLDHashOperator
+ShutdownMediaDecoder(nsRefPtrHashKey<MediaDecoder>* aEntry, void*)
+{
+  aEntry->GetKey()->Shutdown();
+  return PL_DHASH_REMOVE;
+}
+
+static PLDHashOperator
+JoinStateMachineThreads(nsRefPtrHashKey<StateMachineThread>* aEntry, void*)
+{
+  // Hold a strong reference to the StateMachineThread, so that if it
+  // is Unregistered() and the hashtable's owning reference is cleared,
+  // it won't be destroyed while we're spinning here.
+  RefPtr<StateMachineThread> thread = aEntry->GetKey();
+  thread->SpinUntilShutdownComplete();
+  return PL_DHASH_REMOVE;
+}
+
+void
+MediaShutdownManager::Shutdown()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(sInstance);
+
+  // Mark that we're shutting down, so that Unregister(*) calls don't remove
+  // hashtable entries. If Unregsiter(*) was to remove from the hash table,
+  // the iterations over the hashtables below would be disrupted.
+  mIsDoingXPCOMShutDown = true;
+
+  // Iterate over the decoders and shut them down, and remove them from the
+  // hashtable.
+  mDecoders.EnumerateEntries(ShutdownMediaDecoder, nullptr);
+ 
+  // Iterate over the StateMachineThreads and wait for them to have finished
+  // shutting down, and remove them from the hashtable. Once all the decoders
+  // have shutdown the active state machine thread will naturally shutdown
+  // asynchronously. We may also have another state machine thread active,
+  // if construction and shutdown of the state machine thread has interleaved.
+  mStateMachineThreads.EnumerateEntries(JoinStateMachineThreads, nullptr);
+ 
+  // Remove the MediaShutdownManager instance from the shutdown observer
+  // list.
+  nsContentUtils::UnregisterShutdownObserver(this);
+
+  // Clear the singleton instance. The only remaining reference should be the
+  // reference that the observer service used to call us with. The
+  // MediaShutdownManager will be deleted once the observer service cleans
+  // up after it finishes its notifications.
+  sInstance = nullptr;
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/content/media/MediaShutdownManager.h
@@ -0,0 +1,169 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#if !defined(MediaShutdownManager_h_)
+#define MediaShutdownManager_h_
+
+#include "nsIObserver.h"
+#include "mozilla/Monitor.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/StaticPtr.h"
+#include "nsIThread.h"
+#include "nsCOMPtr.h"
+#include "nsTHashtable.h"
+#include "nsHashKeys.h"
+
+namespace mozilla {
+
+class MediaDecoder;
+class StateMachineThread;
+
+// The MediaShutdownManager manages shutting down the MediaDecoder
+// infrastructure in response to an xpcom-shutdown notification. This happens
+// when Gecko is shutting down in the middle of operation. This is tricky, as
+// there are a number of moving parts that must be shutdown in a particular
+// order. Additionally the xpcom-shutdown observer *must* block until all
+// threads are shutdown, which is tricky since we have a number of threads
+// here and their shutdown is asynchronous. We can't have each element of
+// our pipeline listening for xpcom-shutdown, as if each observer blocks
+// waiting for its threads to shutdown it will block other xpcom-shutdown
+// notifications from firing, and shutdown of one part of the media pipeline
+// (say the State Machine thread) may depend another part to be shutdown
+// first (the MediaDecoder threads). Additionally we need to not interfere
+// with shutdown in the the non-xpcom-shutdown case, where we need to be able
+// to recreate the State Machine thread after it's been destroyed without
+// affecting the shutdown of the old State Machine thread. The
+// MediaShutdownManager encapsulates all these dependencies, and provides
+// a single xpcom-shutdown listener for the MediaDecoder infrastructure, to
+// ensure that no shutdown order dependencies leak out of the MediaDecoder
+// stack. The MediaShutdownManager is a singleton.
+//
+// The MediaShutdownManager ensures that the MediaDecoder stack is shutdown
+// before returning from its xpcom-shutdown observer by keeping track of all
+// the active MediaDecoders, and upon xpcom-shutdown calling Shutdown() on
+// every MediaDecoder and then spinning the main thread event loop until the
+// State Machine thread has shutdown. Once the State Machine thread has been
+// shutdown, the xpcom-shutdown observer returns.
+//
+// Note that calling the Unregister() functions may result in the singleton
+// being deleted, so don't store references to the singleton, always use the
+// singleton by derefing the referenced returned by
+// MediaShutdownManager::Instance(), which ensures that the singleton is
+// created when needed.
+// i.e. like this:
+//    MediaShutdownManager::Instance()::Unregister(someDecoder);
+//    MediaShutdownManager::Instance()::Register(someOtherDecoder);
+// Not like this:
+//  MediaShutdownManager& instance = MediaShutdownManager::Instance();
+//  instance.Unregister(someDecoder); // Warning! May delete instance!
+//  instance.Register(someOtherDecoder); // BAD! instance may be dangling!
+class MediaShutdownManager : public nsIObserver {
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+  // The MediaShutdownManager is a singleton, access its instance with
+  // this accessor.
+  static MediaShutdownManager& Instance();
+
+  // Notifies the MediaShutdownManager that it needs to track the shutdown
+  // of this MediaDecoder.
+  void Register(MediaDecoder* aDecoder);
+
+  // Notifies the MediaShutdownManager that a MediaDecoder that it was
+  // tracking has shutdown, and it no longer needs to be shutdown in the
+  // xpcom-shutdown listener.
+  void Unregister(MediaDecoder* aDecoder);
+
+  // Notifies the MediaShutdownManager of a state machine thread that
+  // must be tracked. Note that we track State Machine threads individually
+  // as their shutdown and the construction of a new state machine thread
+  // can interleave. This stores a strong ref to the state machine.
+  void Register(StateMachineThread* aThread);
+
+  // Notifies the MediaShutdownManager that a StateMachineThread that it was
+  // tracking has shutdown, and it no longer needs to be shutdown in the
+  // xpcom-shutdown listener. This drops the strong reference to the
+  // StateMachineThread, which may destroy it.
+  void Unregister(StateMachineThread* aThread);
+
+private:
+
+  MediaShutdownManager();
+  virtual ~MediaShutdownManager();
+
+  void Shutdown();
+
+  // Ensures we have a shutdown listener if we need one, and removes the
+  // listener and destroys the singleton if we don't.
+  void EnsureCorrectShutdownObserverState();
+
+  static StaticRefPtr<MediaShutdownManager> sInstance;
+
+  // References to the MediaDecoder. The decoders unregister themselves
+  // in their Shutdown() method, so we'll drop the reference naturally when
+  // we're shutting down (in the non xpcom-shutdown case).
+  nsTHashtable<nsRefPtrHashKey<MediaDecoder>> mDecoders;
+
+  // References to the state machine threads that we're tracking shutdown
+  // of. Note that although there is supposed to be a single state machine,
+  // the construction and shutdown of these can interleave, so we must track
+  // individual instances of the state machine threads.
+  // These are strong references.
+  nsTHashtable<nsRefPtrHashKey<StateMachineThread>> mStateMachineThreads;
+
+  // True if we have an XPCOM shutdown observer.
+  bool mIsObservingShutdown;
+
+  bool mIsDoingXPCOMShutDown;
+};
+
+// A wrapper for the state machine thread. We must wrap this so that the
+// state machine threads can shutdown independently from the
+// StateMachineTracker, under the control of the MediaShutdownManager.
+// The state machine thread is shutdown naturally when all decoders
+// complete their shutdown. So if a new decoder is created just as the
+// old state machine thread has shutdown, we need to be able to shutdown
+// the old state machine thread independently of the StateMachineTracker
+// creating a new state machine thread. Also if this happens we need to
+// be able to force both state machine threads to shutdown in the
+// MediaShutdownManager, which is why we maintain a set of state machine
+// threads, even though there's supposed to only be one alive at once.
+// This class does not enforce its own thread safety, the StateMachineTracker
+// ensures thread safety when it uses the StateMachineThread.
+class StateMachineThread {
+public:
+  StateMachineThread();
+  ~StateMachineThread();
+
+  NS_INLINE_DECL_REFCOUNTING(StateMachineThread);
+
+  // Creates the wrapped thread.
+  nsresult Init();
+
+  // Returns a reference to the underlying thread. Don't shut this down
+  // directly, use StateMachineThread::Shutdown() instead.
+  nsIThread* GetThread();
+
+  // Dispatches an event to the main thread to shutdown the wrapped thread.
+  // The owner's (StateMachineTracker's) reference to the StateMachineThread
+  // can be dropped, the StateMachineThread will shutdown itself
+  // asynchronously.
+  void Shutdown();
+
+  // Processes events on the main thread event loop until this thread
+  // has been shutdown. Use this to block until the asynchronous shutdown
+  // has complete.
+  void SpinUntilShutdownComplete();
+
+private:
+  void ShutdownThread();
+  nsCOMPtr<nsIThread> mThread;
+};
+
+} // namespace mozilla
+
+#endif
--- a/content/media/moz.build
+++ b/content/media/moz.build
@@ -118,16 +118,17 @@ UNIFIED_SOURCES += [
     'EncodedBufferCache.cpp',
     'FileBlockCache.cpp',
     'MediaCache.cpp',
     'MediaDecoder.cpp',
     'MediaDecoderReader.cpp',
     'MediaDecoderStateMachine.cpp',
     'MediaRecorder.cpp',
     'MediaResource.cpp',
+    'MediaShutdownManager.cpp',
     'MediaStreamGraph.cpp',
     'MediaStreamTrack.cpp',
     'MP3FrameParser.cpp',
     'RtspMediaResource.cpp',
     'StreamBuffer.cpp',
     'TextTrack.cpp',
     'TextTrackCue.cpp',
     'TextTrackCueList.cpp',
--- a/docshell/test/test_bug511449.html
+++ b/docshell/test/test_bug511449.html
@@ -33,18 +33,17 @@ function runTest() {
   SimpleTest.waitForFocus(runNextTest, win);
 }
 
 function runNextTest() {
   var didClose = false;
   win.onunload = function() {
     didClose = true;
   }
-  var utils = SpecialPowers.getDOMWindowUtils(win);
-  utils.sendNativeKeyEvent(0, MAC_VK_ANSI_W, 0x4000 /* cmd */, "w", "w");
+  synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, MAC_VK_ANSI_W, {metaKey:1}, "w", "w");
 
   setTimeout(function () {
     ok(didClose, "Cmd+W should have closed the tab");
     if (!didClose) {
       win.close();
     }
     SimpleTest.finish();
   }, 1000);
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2129,28 +2129,19 @@ class CGConstructorEnabledViaFunc(CGAbst
                                    Argument("JS::Handle<JSObject*>", "obj")])
 
     def definition_body(self):
         func = self.descriptor.interface.getExtendedAttribute("Func")
         assert isinstance(func, list) and len(func) == 1
         return "  return %s(cx, obj);" % func[0]
 
 def CreateBindingJSObject(descriptor, properties, parent):
-    # When we have unforgeable properties, we're going to define them
-    # on our object, so we have to root it when we create it, so it
-    # won't suddenly die while defining the unforgeables.  Similarly,
-    # if we have members in slots we'll have to call the getters which
-    # could also GC.
-    needRoot = (properties.unforgeableAttrs.hasNonChromeOnly() or
-                properties.unforgeableAttrs.hasChromeOnly() or
-                descriptor.interface.hasMembersInSlots())
-    if needRoot:
-        objDecl = "  JS::Rooted<JSObject*> obj(aCx);\n"
-    else:
-        objDecl = "  JSObject *obj;\n"
+    # We don't always need to root obj, but there are a variety
+    # of cases where we do, so for simplicity, just always root it.
+    objDecl = "  JS::Rooted<JSObject*> obj(aCx);\n"
     if descriptor.proxy:
         create = """  JS::Rooted<JS::Value> proxyPrivateVal(aCx, JS::PrivateValue(aObject));
   obj = NewProxyObject(aCx, DOMProxyHandler::getInstance(),
                        proxyPrivateVal, proto, %s);
   if (!obj) {
     return nullptr;
   }
 
--- a/dom/bluetooth/bluedroid/gonk/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth/bluedroid/gonk/BluetoothServiceBluedroid.cpp
@@ -241,17 +241,18 @@ GetBluetoothInterface()
 {
   return sBtInterface;
 }
 
 void
 StringToBdAddressType(const nsAString& aBdAddress,
                       bt_bdaddr_t *aRetBdAddressType)
 {
-  const char* str = NS_ConvertUTF16toUTF8(aBdAddress).get();
+  NS_ConvertUTF16toUTF8 bdAddressUTF8(aBdAddress);
+  const char* str = bdAddressUTF8.get();
 
   for (int i = 0; i < 6; i++) {
     aRetBdAddressType->address[i] = (uint8_t) strtoul(str, (char **)&str, 16);
     str++;
   }
 }
 
 void
@@ -977,17 +978,17 @@ BluetoothServiceBluedroid::SetProperty(B
     DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
 
     return NS_OK;
   }
 
   const nsString propName = aValue.name();
   bt_property_t prop;
   bt_scan_mode_t scanMode;
-  nsString str;
+  nsCString str;
 
   // For Bluedroid, it's necessary to check property name for SetProperty
   if (propName.EqualsLiteral("Name")) {
     prop.type = BT_PROPERTY_BDNAME;
   } else if (propName.EqualsLiteral("Discoverable")) {
     prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE;
   } else if (propName.EqualsLiteral("DiscoverableTimeout")) {
     prop.type = BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT;
@@ -995,18 +996,18 @@ BluetoothServiceBluedroid::SetProperty(B
     BT_LOGR("Warning: Property type is not supported yet, type: %d", prop.type);
   }
 
   if (aValue.value().type() == BluetoothValue::Tuint32_t) {
     // Set discoverable timeout
     prop.val = (void*)aValue.value().get_uint32_t();
   } else if (aValue.value().type() == BluetoothValue::TnsString) {
     // Set name
-    str = aValue.value().get_nsString();
-    const char* name = NS_ConvertUTF16toUTF8(str).get();
+    str = NS_ConvertUTF16toUTF8(aValue.value().get_nsString());
+    const char* name = str.get();
     prop.val = (void*)name;
     prop.len = strlen(name);
   } else if (aValue.value().type() == BluetoothValue::Tbool) {
     scanMode = aValue.value().get_bool() ?
                  BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE :
                  BT_SCAN_MODE_CONNECTABLE;
 
     prop.val = (void*)&scanMode;
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -203,16 +203,23 @@ public:
 
     nsCOMPtr<nsIPermissionManager> permManager = do_GetService("@mozilla.org/permissionmanager;1");
     return permManager->RemovePermissionsForApp(appId, browserOnly);
   }
 };
 
 NS_IMPL_ISUPPORTS1(AppClearDataObserver, nsIObserver)
 
+static bool
+IsExpandedPrincipal(nsIPrincipal* aPrincipal)
+{
+  nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(aPrincipal);
+  return !!ep;
+}
+
 } // anonymous namespace
 
 ////////////////////////////////////////////////////////////////////////////////
 
 nsPermissionManager::PermissionKey::PermissionKey(nsIPrincipal* aPrincipal)
 {
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(GetHostForPrincipal(aPrincipal, mHost)));
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aPrincipal->GetAppId(&mAppId)));
@@ -639,16 +646,21 @@ nsPermissionManager::AddFromPrincipal(ns
   }
 
   // We don't add the system principal because it actually has no URI and we
   // always allow action for them.
   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
     return NS_OK;
   }
 
+  // Permissions may not be added to expanded principals.
+  if (IsExpandedPrincipal(aPrincipal)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
   return AddInternal(aPrincipal, nsDependentCString(aType), aPermission, 0,
                      aExpireType, aExpireTime, eNotify, eWriteToDB);
 }
 
 nsresult
 nsPermissionManager::AddInternal(nsIPrincipal* aPrincipal,
                                  const nsAFlatCString &aType,
                                  uint32_t              aPermission,
@@ -869,16 +881,21 @@ nsPermissionManager::RemoveFromPrincipal
   NS_ENSURE_ARG_POINTER(aPrincipal);
   NS_ENSURE_ARG_POINTER(aType);
 
   // System principals are never added to the database, no need to remove them.
   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
     return NS_OK;
   }
 
+  // Permissions may not be added to expanded principals.
+  if (IsExpandedPrincipal(aPrincipal)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
   // AddInternal() handles removal, just let it do the work
   return AddInternal(aPrincipal,
                      nsDependentCString(aType),
                      nsIPermissionManager::UNKNOWN_ACTION,
                      0,
                      nsIPermissionManager::EXPIRE_NEVER,
                      0,
                      eNotify,
@@ -953,40 +970,24 @@ nsPermissionManager::TestExactPermission
   return TestExactPermissionFromPrincipal(principal, aType, aPermission);
 }
 
 NS_IMETHODIMP
 nsPermissionManager::TestExactPermissionFromPrincipal(nsIPrincipal* aPrincipal,
                                                       const char* aType,
                                                       uint32_t* aPermission)
 {
-  NS_ENSURE_ARG_POINTER(aPrincipal);
-
-  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
-    *aPermission = nsIPermissionManager::ALLOW_ACTION;
-    return NS_OK;
-  }
-
   return CommonTestPermission(aPrincipal, aType, aPermission, true, true);
 }
 
 NS_IMETHODIMP
 nsPermissionManager::TestExactPermanentPermission(nsIPrincipal* aPrincipal,
                                                   const char* aType,
                                                   uint32_t* aPermission)
 {
-  NS_ENSURE_ARG_POINTER(aPrincipal);
-
-  // System principals do not have URI so we can't try to get
-  // retro-compatibility here.
-  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
-    *aPermission = nsIPermissionManager::ALLOW_ACTION;
-    return NS_OK;
-  }
-
   return CommonTestPermission(aPrincipal, aType, aPermission, true, false);
 }
 
 NS_IMETHODIMP
 nsPermissionManager::TestPermission(nsIURI     *aURI,
                                     const char *aType,
                                     uint32_t   *aPermission)
 {
@@ -1017,25 +1018,16 @@ nsPermissionManager::TestPermissionFromW
   return TestPermissionFromPrincipal(principal, aType, aPermission);
 }
 
 NS_IMETHODIMP
 nsPermissionManager::TestPermissionFromPrincipal(nsIPrincipal* aPrincipal,
                                                  const char* aType,
                                                  uint32_t* aPermission)
 {
-  NS_ENSURE_ARG_POINTER(aPrincipal);
-
-  // System principals do not have URI so we can't try to get
-  // retro-compatibility here.
-  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
-    *aPermission = nsIPermissionManager::ALLOW_ACTION;
-    return NS_OK;
-  }
-
   return CommonTestPermission(aPrincipal, aType, aPermission, false, true);
 }
 
 NS_IMETHODIMP
 nsPermissionManager::GetPermissionObject(nsIPrincipal* aPrincipal,
                                          const char* aType,
                                          bool aExactHostMatch,
                                          nsIPermission** aResult)
@@ -1044,16 +1036,21 @@ nsPermissionManager::GetPermissionObject
   NS_ENSURE_ARG_POINTER(aType);
 
   *aResult = nullptr;
 
   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
     return NS_OK;
   }
 
+  // Querying the permission object of an nsEP is non-sensical.
+  if (IsExpandedPrincipal(aPrincipal)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
   nsAutoCString host;
   nsresult rv = GetHostForPrincipal(aPrincipal, host);
   NS_ENSURE_SUCCESS(rv, rv);
 
   int32_t typeIndex = GetTypeIndex(aType, false);
   // If type == -1, the type isn't known,
   // so just return NS_OK
   if (typeIndex == -1) return NS_OK;
@@ -1096,16 +1093,49 @@ nsPermissionManager::CommonTestPermissio
                                           const char *aType,
                                           uint32_t   *aPermission,
                                           bool        aExactHostMatch,
                                           bool        aIncludingSession)
 {
   NS_ENSURE_ARG_POINTER(aPrincipal);
   NS_ENSURE_ARG_POINTER(aType);
 
+  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
+    *aPermission = nsIPermissionManager::ALLOW_ACTION;
+    return NS_OK;
+  }
+
+  // For expanded principals, we want to iterate over the whitelist and see
+  // if the permission is granted for any of them.
+  nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(aPrincipal);
+  if (ep) {
+    nsTArray<nsCOMPtr<nsIPrincipal>>* whitelist;
+    nsresult rv = ep->GetWhiteList(&whitelist);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Start with DENY_ACTION. If we get PROMPT_ACTION, keep going to see if
+    // we get ALLOW_ACTION from another principal.
+    *aPermission = nsIPermissionManager::DENY_ACTION;
+    for (size_t i = 0; i < whitelist->Length(); ++i) {
+      uint32_t perm;
+      rv = CommonTestPermission(whitelist->ElementAt(i), aType, &perm, aExactHostMatch,
+                                aIncludingSession);
+      NS_ENSURE_SUCCESS(rv, rv);
+      if (perm == nsIPermissionManager::ALLOW_ACTION) {
+        *aPermission = perm;
+        return NS_OK;
+      } else if (perm == nsIPermissionManager::PROMPT_ACTION) {
+        // Store it, but keep going to see if we can do better.
+        *aPermission = perm;
+      }
+    }
+
+    return NS_OK;
+  }
+
   // set the default
   *aPermission = nsIPermissionManager::UNKNOWN_ACTION;
 
   nsAutoCString host;
   nsresult rv = GetHostForPrincipal(aPrincipal, host);
   NS_ENSURE_SUCCESS(rv, rv);
 
   int32_t typeIndex = GetTypeIndex(aType, false);
@@ -1833,16 +1863,21 @@ nsPermissionManager::UpdateExpireTime(ns
   if (aSessionExpireTime < nowms || aPersistentExpireTime < nowms) {
     return NS_ERROR_INVALID_ARG;
   }
 
   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
     return NS_OK;
   }
 
+  // Setting the expire time of an nsEP is non-sensical.
+  if (IsExpandedPrincipal(aPrincipal)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
   nsAutoCString host;
   nsresult rv = GetHostForPrincipal(aPrincipal, host);
   NS_ENSURE_SUCCESS(rv, rv);
 
   int32_t typeIndex = GetTypeIndex(aType, false);
   // If type == -1, the type isn't known,
   // so just return NS_OK
   if (typeIndex == -1) return NS_OK;
--- a/js/src/config/Makefile.in
+++ b/js/src/config/Makefile.in
@@ -31,17 +31,16 @@ include $(topsrcdir)/config/rules.mk
 
 HOST_CFLAGS += -DUNICODE -D_UNICODE
 
 ifdef WRAP_SYSTEM_INCLUDES
 export:: \
   $(call mkdir_deps,system_wrappers_js) \
   $(NULL)
 	$(PYTHON) -m mozbuild.action.preprocessor $(DEFINES) $(ACDEFINES) \
-		-DMOZ_NATIVE_ICU=$(MOZ_NATIVE_ICU) \
 		$(srcdir)/system-headers | $(PERL) $(srcdir)/make-system-wrappers.pl system_wrappers_js
 	$(INSTALL) system_wrappers_js $(DIST)
 
 GARBAGE_DIRS += system_wrappers_js
 endif
 
 GARBAGE += $(srcdir)/*.pyc *.pyc
 
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -4160,16 +4160,17 @@ ICU_LIB_NAMES=
 MOZ_NATIVE_ICU=
 MOZ_ARG_WITH_BOOL(system-icu,
 [  --with-system-icu
                           Use system ICU (located with pkgconfig)],
     MOZ_NATIVE_ICU=1)
 
 if test -n "$MOZ_NATIVE_ICU"; then
     PKG_CHECK_MODULES(MOZ_ICU, icu-i18n >= 50.1)
+    MOZ_SHARED_ICU=1
 fi
 
 MOZ_ARG_WITH_STRING(intl-api,
 [  --with-intl-api, --with-intl-api=build, --without-intl-api
     Determine the status of the ECMAScript Internationalization API.  The first
     (or lack of any of these) builds and exposes the API.  The second builds it
     but doesn't use ICU or expose the API to script.  The third doesn't build
     ICU at all.],
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -642,16 +642,27 @@ js::TraceWeakMaps(WeakMapTracer *trc)
 }
 
 extern JS_FRIEND_API(bool)
 js::AreGCGrayBitsValid(JSRuntime *rt)
 {
     return rt->gcGrayBitsValid;
 }
 
+JS_FRIEND_API(bool)
+js::ZoneGlobalsAreAllGray(JS::Zone *zone)
+{
+    for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
+        JSObject *obj = comp->maybeGlobal();
+        if (!obj || !JS::GCThingIsMarkedGray(obj))
+            return false;
+    }
+    return true;
+}
+
 JS_FRIEND_API(JSGCTraceKind)
 js::GCThingTraceKind(void *thing)
 {
     JS_ASSERT(thing);
     return gc::GetGCThingTraceKind(thing);
 }
 
 JS_FRIEND_API(void)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -334,16 +334,19 @@ struct WeakMapTracer {
 };
 
 extern JS_FRIEND_API(void)
 TraceWeakMaps(WeakMapTracer *trc);
 
 extern JS_FRIEND_API(bool)
 AreGCGrayBitsValid(JSRuntime *rt);
 
+extern JS_FRIEND_API(bool)
+ZoneGlobalsAreAllGray(JS::Zone *zone);
+
 typedef void
 (*GCThingCallback)(void *closure, void *gcthing);
 
 extern JS_FRIEND_API(void)
 VisitGrayWrapperTargets(JS::Zone *zone, GCThingCallback callback, void *closure);
 
 extern JS_FRIEND_API(JSObject *)
 GetWeakmapKeyDelegate(JSObject *key);
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1633,17 +1633,17 @@ TemporaryTypeSet::isDOMClass()
 
     unsigned count = getObjectCount();
     for (unsigned i = 0; i < count; i++) {
         const Class *clasp = getObjectClass(i);
         if (clasp && !(clasp->flags & JSCLASS_IS_DOMJSCLASS))
             return false;
     }
 
-    return true;
+    return count > 0;
 }
 
 bool
 TemporaryTypeSet::maybeCallable()
 {
     if (!maybeObject())
         return false;
 
--- a/js/xpconnect/src/XPCWrappedJS.cpp
+++ b/js/xpconnect/src/XPCWrappedJS.cpp
@@ -220,17 +220,18 @@ nsXPCWrappedJS::QueryInterface(REFNSIID 
 
 nsrefcnt
 nsXPCWrappedJS::AddRef(void)
 {
     if (!MOZ_LIKELY(NS_IsMainThread()))
         MOZ_CRASH();
 
     MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");
-    nsrefcnt cnt = mRefCnt.incr();
+    nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Upcast(this);
+    nsrefcnt cnt = mRefCnt.incr(base);
     NS_LOG_ADDREF(this, cnt, "nsXPCWrappedJS", sizeof(*this));
 
     if (2 == cnt && IsValid()) {
         GetJSObject(); // Unmark gray JSObject.
         mClass->GetRuntime()->AddWrappedJSRoot(this);
     }
 
     return cnt;
@@ -249,17 +250,17 @@ nsXPCWrappedJS::Release(void)
     nsrefcnt cnt = mRefCnt.decr(base, &shouldDelete);
     NS_LOG_RELEASE(this, cnt, "nsXPCWrappedJS");
 
     if (0 == cnt) {
         if (MOZ_UNLIKELY(shouldDelete)) {
             mRefCnt.stabilizeForDeletion();
             DeleteCycleCollectable();
         } else {
-            mRefCnt.incr();
+            mRefCnt.incr(base);
             Destroy();
             mRefCnt.decr(base);
         }
     } else if (1 == cnt) {
         if (IsValid())
             RemoveFromRootSet();
 
         // If we are not a root wrapper being used from a weak reference,
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -2256,21 +2256,22 @@ ContainerState::ProcessDisplayItems(cons
       // into its buffer even if they're currently covered.
       if (itemVisibleRect.IsEmpty() &&
           !item->ShouldBuildLayerEvenIfInvisible(mBuilder)) {
         continue;
       }
 
 
       nsDisplayItem::Type type = item->GetType();
-      bool setVisibleRegion = type != nsDisplayItem::TYPE_TRANSFORM;
-      if (setVisibleRegion) {
+      bool setVisibleRegion = (type != nsDisplayItem::TYPE_TRANSFORM) &&
+        (type != nsDisplayItem::TYPE_SCROLL_LAYER);
+      if (type == nsDisplayItem::TYPE_TRANSFORM) {
+        mParameters.mAncestorClipRect = itemClip.HasClip() ? &clipRect : nullptr;
+      } else {
         mParameters.mAncestorClipRect = nullptr;
-      } else {
-        mParameters.mAncestorClipRect = itemClip.HasClip() ? &clipRect : nullptr;
       }
 
       // Just use its layer.
       nsRefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager, mParameters);
       if (!ownLayer) {
         continue;
       }
 
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -4857,16 +4857,18 @@ nsContextBoxBlur::BlurRectangle(gfxConte
   // Chrome/Skia always does the blurs in device space
   // and will sometimes get incorrect results (e.g. rotated blurs)
   gfxMatrix transform = aDestinationCtx->CurrentMatrix();
   // XXX: we could probably handle negative scales but for now it's easier just to fallback
   if (!transform.HasNonAxisAlignedTransform() && transform.xx > 0.0 && transform.yy > 0.0) {
     scaleX = transform.xx;
     scaleY = transform.yy;
     aDestinationCtx->IdentityMatrix();
+  } else {
+    transform = gfxMatrix();
   }
 
   gfxPoint blurStdDev = ComputeBlurStdDev(aBlurRadius, aAppUnitsPerDevPixel, scaleX, scaleY);
 
   gfxRect dirtyRect =
     nsLayoutUtils::RectToGfxRect(aDirtyRect, aAppUnitsPerDevPixel);
   dirtyRect.RoundOut();
 
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -3479,16 +3479,27 @@ nsDisplayScrollLayer::nsDisplayScrollLay
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplayScrollLayer::~nsDisplayScrollLayer()
 {
   MOZ_COUNT_DTOR(nsDisplayScrollLayer);
 }
 #endif
 
+nsRect
+nsDisplayScrollLayer::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
+{
+  nsIScrollableFrame* sf = do_QueryFrame(mScrollFrame);
+  if (sf) {
+    *aSnap = false;
+    return sf->GetScrollPortRect() + aBuilder->ToReferenceFrame(mScrollFrame);
+  }
+  return nsDisplayWrapList::GetBounds(aBuilder, aSnap);
+}
+
 already_AddRefed<Layer>
 nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
                                  LayerManager* aManager,
                                  const ContainerLayerParameters& aContainerParameters) {
   nsRefPtr<ContainerLayer> layer = aManager->GetLayerBuilder()->
     BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
                            aContainerParameters, nullptr);
 
@@ -3505,17 +3516,17 @@ nsDisplayScrollLayer::BuildLayer(nsDispl
   bool usingCriticalDisplayport = false;
   nsRect displayport, criticalDisplayport;
   if (content) {
     usingDisplayport = nsLayoutUtils::GetDisplayPort(content, &displayport);
     usingCriticalDisplayport =
       nsLayoutUtils::GetCriticalDisplayPort(content, &criticalDisplayport);
   }
   RecordFrameMetrics(mScrolledFrame, mScrollFrame, ReferenceFrame(), layer,
-                     mVisibleRect, viewport,
+                     mList.GetVisibleRect(), viewport,
                      (usingDisplayport ? &displayport : nullptr),
                      (usingCriticalDisplayport ? &criticalDisplayport : nullptr),
                      scrollId, false, aContainerParameters);
 
   return layer.forget();
 }
 
 bool
@@ -3529,38 +3540,39 @@ nsDisplayScrollLayer::ShouldBuildLayerEv
 }
 
 bool
 nsDisplayScrollLayer::ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                         nsRegion* aVisibleRegion,
                                         const nsRect& aAllowVisibleRegionExpansion)
 {
   nsRect displayport;
-  if (nsLayoutUtils::GetDisplayPort(mScrolledFrame->GetContent(), &displayport)) {
+  bool usingDisplayPort =
+    nsLayoutUtils::GetDisplayPort(mScrolledFrame->GetContent(), &displayport);
+  nsRegion childVisibleRegion;
+  if (usingDisplayPort) {
     // The visible region for the children may be much bigger than the hole we
     // are viewing the children from, so that the compositor process has enough
     // content to asynchronously pan while content is being refreshed.
-
-    nsRegion childVisibleRegion = displayport + mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
-
-    nsRect boundedRect =
-      childVisibleRegion.GetBounds().Intersect(mList.GetBounds(aBuilder));
-    nsRect allowExpansion = boundedRect.Intersect(aAllowVisibleRegionExpansion);
-    bool visible = mList.ComputeVisibilityForSublist(
-      aBuilder, &childVisibleRegion, boundedRect, allowExpansion);
-    // We don't allow this computation to influence aVisibleRegion, on the
-    // assumption that the layer can be asynchronously scrolled so we'll
-    // definitely need all the content under it.
-    mVisibleRect = boundedRect;
-
-    return visible;
+    childVisibleRegion = displayport + mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
   } else {
-    return nsDisplayWrapList::ComputeVisibility(aBuilder, aVisibleRegion,
-                                                aAllowVisibleRegionExpansion);
+    bool snap;
+    childVisibleRegion = GetBounds(aBuilder, &snap);
   }
+
+  nsRect boundedRect =
+    childVisibleRegion.GetBounds().Intersect(mList.GetBounds(aBuilder));
+  nsRect allowExpansion = boundedRect.Intersect(aAllowVisibleRegionExpansion);
+  bool visible = mList.ComputeVisibilityForSublist(
+    aBuilder, &childVisibleRegion, boundedRect, allowExpansion);
+  // We don't allow this computation to influence aVisibleRegion, on the
+  // assumption that the layer can be asynchronously scrolled so we'll
+  // definitely need all the content under it.
+
+  return visible;
 }
 
 LayerState
 nsDisplayScrollLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
                                     LayerManager* aManager,
                                     const ContainerLayerParameters& aParameters)
 {
   // Force this as a layer so we can scroll asynchronously.
@@ -3663,16 +3675,22 @@ nsDisplayScrollInfoLayer::nsDisplayScrol
 
 nsDisplayScrollInfoLayer::~nsDisplayScrollInfoLayer()
 {
   FrameProperties props = mScrolledFrame->Properties();
   props.Remove(nsIFrame::ScrollLayerCount());
   MOZ_COUNT_DTOR(nsDisplayScrollInfoLayer);
 }
 
+nsRect
+nsDisplayScrollInfoLayer::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
+{
+  return nsDisplayWrapList::GetBounds(aBuilder, aSnap);
+}
+
 LayerState
 nsDisplayScrollInfoLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
                                         LayerManager* aManager,
                                         const ContainerLayerParameters& aParameters)
 {
   return LAYER_ACTIVE_EMPTY;
 }
 
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1507,16 +1507,18 @@ public:
   void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                nsDisplayItem::HitTestState* aState,
                nsTArray<nsIFrame*> *aOutFrames) const;
 
 #ifdef DEBUG
   bool DidComputeVisibility() const { return mDidComputeVisibility; }
 #endif
 
+  nsRect GetVisibleRect() const { return mVisibleRect; }
+
 private:
   // This class is only used on stack, so we don't have to worry about leaking
   // it.  Don't let us be heap-allocated!
   void* operator new(size_t sz) CPP_THROW_NEW;
   
   // Utility function used to massage the list during ComputeVisibility.
   void FlattenTo(nsTArray<nsDisplayItem*>* aElements);
   
@@ -2704,16 +2706,18 @@ public:
                        nsIFrame* aForFrame, nsIFrame* aScrolledFrame,
                        nsIFrame* aScrollFrame);
   NS_DISPLAY_DECL_NAME("ScrollLayer", TYPE_SCROLL_LAYER)
 
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayScrollLayer();
 #endif
 
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
+
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE;
 
   virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
 
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
@@ -2755,16 +2759,18 @@ class nsDisplayScrollInfoLayer : public 
 {
 public:
   nsDisplayScrollInfoLayer(nsDisplayListBuilder* aBuilder,
                            nsIFrame* aScrolledFrame, nsIFrame* aScrollFrame);
   NS_DISPLAY_DECL_NAME("ScrollInfoLayer", TYPE_SCROLL_INFO_LAYER)
 
   virtual ~nsDisplayScrollInfoLayer();
 
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
+
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) MOZ_OVERRIDE;
   virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
   { return true; }
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder,
                           nsDisplayItem* aItem) MOZ_OVERRIDE;
 
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -118,22 +118,58 @@ nsPresContext::MakeColorPref(const nsStr
   }
 
   nscolor color;
   return nsRuleNode::ComputeColor(value, this, nullptr, color)
     ? color
     : NS_RGB(0, 0, 0);
 }
 
+static void DumpPresContextState(nsPresContext* aPC)
+{
+  printf_stderr("PresContext(%p) ", aPC);
+  nsIURI* uri = aPC->Document()->GetDocumentURI();
+  if (uri) {
+    nsAutoCString uriSpec;
+    nsresult rv = uri->GetSpec(uriSpec);
+    if (NS_SUCCEEDED(rv)) {
+      printf_stderr("%s ", uriSpec.get());
+    }
+  }
+  nsIPresShell* shell = aPC->GetPresShell();
+  if (shell) {
+    printf_stderr("PresShell(%p) - IsDestroying(%i) IsFrozen(%i) IsActive(%i) IsVisible(%i) IsNeverPainting(%i) GetRootFrame(%p)",
+                  shell->IsDestroying(),
+                  shell->IsFrozen(),
+                  shell->IsActive(),
+                  shell->IsVisible(),
+                  shell->IsNeverPainting(),
+                  shell->GetRootFrame());
+  }
+  printf_stderr("\n");
+}
+
 bool
 nsPresContext::IsDOMPaintEventPending() 
 {
   if (mFireAfterPaintEvents) {
     return true;
   }
+  if (!GetDisplayRootPresContext() ||
+      !GetDisplayRootPresContext()->GetRootPresContext()) {
+    printf_stderr("Failed to find root pres context, dumping pres context and ancestors\n");
+    nsPresContext* pc = this;
+    for (;;) {
+      DumpPresContextState(pc);
+      nsPresContext* parent = pc->GetParentPresContext();
+      if (!parent)
+        break;
+      pc = parent;
+    }
+  }
   if (GetDisplayRootPresContext()->GetRootPresContext()->mRefreshDriver->ViewManagerFlushIsPending()) {
     // Since we're promising that there will be a MozAfterPaint event
     // fired, we record an empty invalidation in case display list
     // invalidation doesn't invalidate anything further.
     NotifyInvalidation(nsRect(0, 0, 0, 0), 0);
     NS_ASSERTION(mFireAfterPaintEvents, "Why aren't we planning to fire the event?");
     return true;
   }
--- a/testing/mochitest/tests/SimpleTest/EventUtils.js
+++ b/testing/mochitest/tests/SimpleTest/EventUtils.js
@@ -615,20 +615,57 @@ function _parseNativeModifiers(aModifier
   if (aModifiers.accelKey) {
     modifiers |=
       (navigator.platform.indexOf("Mac") == 0) ? 0x00004000 : 0x00000400;
   }
   if (aModifiers.accelRightKey) {
     modifiers |=
       (navigator.platform.indexOf("Mac") == 0) ? 0x00008000 : 0x00000800;
   }
+  if (aModifiers.altGrKey) {
+    modifiers |=
+      (navigator.platform.indexOf("Win") == 0) ? 0x00002800 : 0x00001000;
+  }
   return modifiers;
 }
 
-const KEYBOARD_LAYOUT_EN_US = 0;
+// Mac: Any unused number is okay for adding new keyboard layout.
+//      When you add new keyboard layout here, you need to modify
+//      TISInputSourceWrapper::InitByLayoutID().
+// Win: These constants can be found by inspecting registry keys under
+//      HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Keyboard Layouts
+
+const KEYBOARD_LAYOUT_ARABIC =
+  { name: "Arabic",             Mac: 6,    Win: 0x00000401 };
+const KEYBOARD_LAYOUT_BRAZILIAN_ABNT =
+  { name: "Brazilian ABNT",     Mac: null, Win: 0x00000416 };
+const KEYBOARD_LAYOUT_DVORAK_QWERTY =
+  { name: "Dvorak-QWERTY",      Mac: 4,    Win: null       };
+const KEYBOARD_LAYOUT_EN_US =
+  { name: "US",                 Mac: 0,    Win: 0x00000409 };
+const KEYBOARD_LAYOUT_FRENCH =
+  { name: "French",             Mac: 7,    Win: 0x0000040C };
+const KEYBOARD_LAYOUT_GREEK =
+  { name: "Greek",              Mac: 1,    Win: 0x00000408 };
+const KEYBOARD_LAYOUT_GERMAN =
+  { name: "German",             Mac: 2,    Win: 0x00000407 };
+const KEYBOARD_LAYOUT_HEBREW =
+  { name: "Hebrew",             Mac: 8,    Win: 0x0000040D };
+const KEYBOARD_LAYOUT_JAPANESE =
+  { name: "Japanese",           Mac: null, Win: 0x00000411 };
+const KEYBOARD_LAYOUT_LITHUANIAN =
+  { name: "Lithuanian",         Mac: 9,    Win: 0x00010427 };
+const KEYBOARD_LAYOUT_NORWEGIAN =
+  { name: "Norwegian",          Mac: 10,   Win: 0x00000414 };
+const KEYBOARD_LAYOUT_SPANISH =
+  { name: "Spanish",            Mac: 11,   Win: 0x0000040A };
+const KEYBOARD_LAYOUT_SWEDISH =
+  { name: "Swedish",            Mac: 3,    Win: 0x0000041D };
+const KEYBOARD_LAYOUT_THAI =
+  { name: "Thai",               Mac: 5,    Win: 0x0002041E };
 
 /**
  * synthesizeNativeKey() dispatches native key event on active window.
  * This is implemented only on Windows and Mac.
  *
  * @param aKeyboardLayout       One of KEYBOARD_LAYOUT_* defined above.
  * @param aNativeKeyCode        A native keycode value defined in
  *                              NativeKeyCodes.js.
@@ -646,34 +683,23 @@ const KEYBOARD_LAYOUT_EN_US = 0;
 
 function synthesizeNativeKey(aKeyboardLayout, aNativeKeyCode, aModifiers,
                              aChars, aUnmodifiedChars)
 {
   var utils = _getDOMWindowUtils(window);
   if (!utils) {
     return false;
   }
-  var nativeKeyboardLayout;
+  var nativeKeyboardLayout = null;
   if (navigator.platform.indexOf("Mac") == 0) {
-    switch (aKeyboardLayout) {
-      case KEYBOARD_LAYOUT_EN_US:
-        nativeKeyboardLayout = 0;
-        break;
-      default:
-        return false;
-    }
+    nativeKeyboardLayout = aKeyboardLayout.Mac;
   } else if (navigator.platform.indexOf("Win") == 0) {
-    switch (aKeyboardLayout) {
-      case KEYBOARD_LAYOUT_EN_US:
-        nativeKeyboardLayout = 0x409;
-        break;
-      default:
-        return false;
-    }
-  } else {
+    nativeKeyboardLayout = aKeyboardLayout.Win;
+  }
+  if (nativeKeyboardLayout === null) {
     return false;
   }
   utils.sendNativeKeyEvent(nativeKeyboardLayout, aNativeKeyCode,
                            _parseNativeModifiers(aModifiers),
                            aChars, aUnmodifiedChars);
   return true;
 }
 
--- a/testing/mochitest/tests/SimpleTest/NativeKeyCodes.js
+++ b/testing/mochitest/tests/SimpleTest/NativeKeyCodes.js
@@ -1,11 +1,11 @@
 /**
- * This file defines all virtual keycodes for
- * nsIDOMWindowUtils.sendNativeKeyEvent()
+ * This file defines all virtual keycodes for synthesizeNativeKey() of
+ * EventUtils.js and nsIDOMWindowUtils.sendNativeKeyEvent().
  * These values are defined in each platform's SDK or documents.
  */
 
 // Windows
 
 const WIN_VK_LBUTTON                    = 0x01;
 const WIN_VK_RBUTTON                    = 0x02;
 const WIN_VK_CANCEL                     = 0x03;
--- a/toolkit/content/tests/browser/browser.ini
+++ b/toolkit/content/tests/browser/browser.ini
@@ -1,10 +1,11 @@
 [DEFAULT]
 
 [browser_browserDrop.js]
 [browser_bug295977_autoscroll_overflow.js]
 [browser_bug594509.js]
 [browser_default_image_filename.js]
 [browser_findbar.js]
+skip-if = os == "linux" # Bug 945667
 [browser_input_file_tooltips.js]
 [browser_keyevents_during_autoscrolling.js]
 [browser_save_resend_postdata.js]
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -662,22 +662,18 @@ AndroidGeckoEvent::MakeTouchEvent(nsIWid
     }
 
     WidgetTouchEvent event(true, type, widget);
     if (type == NS_EVENT_NULL) {
         // An event we don't know about
         return event;
     }
 
-    event.modifiers = 0;
+    event.modifiers = DOMModifiers();
     event.time = Time();
-    event.InitBasicModifiers(IsCtrlPressed(),
-                             IsAltPressed(),
-                             IsShiftPressed(),
-                             IsMetaPressed());
 
     const nsIntPoint& offset = widget->WidgetToScreenOffset();
     event.touches.SetCapacity(endIndex - startIndex);
     for (int i = startIndex; i < endIndex; i++) {
         // In this code branch, we are dispatching this event directly
         // into Gecko (as opposed to going through the AsyncPanZoomController),
         // and the Points() array has points in CSS pixels, which we need
         // to convert.
@@ -728,28 +724,17 @@ AndroidGeckoEvent::MakeMultiTouchInput(n
         case AndroidMotionEvent::ACTION_OUTSIDE:
         case AndroidMotionEvent::ACTION_CANCEL: {
             type = MultiTouchInput::MULTITOUCH_CANCEL;
             break;
         }
     }
 
     MultiTouchInput event(type, Time(), 0);
-    if (IsCtrlPressed()) {
-      event.modifiers |= MODIFIER_CONTROL;
-    }
-    if (IsAltPressed()) {
-      event.modifiers |= MODIFIER_ALT;
-    }
-    if (IsShiftPressed()) {
-      event.modifiers |= MODIFIER_SHIFT;
-    }
-    if (IsMetaPressed()) {
-      event.modifiers |= MODIFIER_META;
-    }
+    event.modifiers = DOMModifiers();
 
     if (type < 0) {
         // An event we don't know about
         return event;
     }
 
     const nsIntPoint& offset = widget->WidgetToScreenOffset();
     event.mTouches.SetCapacity(endIndex - startIndex);
@@ -797,30 +782,61 @@ AndroidGeckoEvent::MakeMouseEvent(nsIWid
         return event;
     }
 
     // XXX can we synthesize different buttons?
     event.button = WidgetMouseEvent::eLeftButton;
     if (msg != NS_MOUSE_MOVE) {
         event.clickCount = 1;
     }
-    event.modifiers = 0;
+    event.modifiers = DOMModifiers();
     event.time = Time();
 
     // We are dispatching this event directly into Gecko (as opposed to going
     // through the AsyncPanZoomController), and the Points() array has points
     // in CSS pixels, which we need to convert to LayoutDevice pixels.
     const nsIntPoint& offset = widget->WidgetToScreenOffset();
     CSSToLayoutDeviceScale scale = widget->GetDefaultScale();
     event.refPoint = LayoutDeviceIntPoint((Points()[0].x * scale.scale) - offset.x,
                                           (Points()[0].y * scale.scale) - offset.y);
 
     return event;
 }
 
+Modifiers
+AndroidGeckoEvent::DOMModifiers() const
+{
+    Modifiers result = 0;
+    if (mMetaState & AMETA_ALT_MASK) {
+        result |= MODIFIER_ALT;
+    }
+    if (mMetaState & AMETA_SHIFT_MASK) {
+        result |= MODIFIER_SHIFT;
+    }
+    if (mMetaState & AMETA_CTRL_MASK) {
+        result |= MODIFIER_CONTROL;
+    }
+    if (mMetaState & AMETA_META_MASK) {
+        result |= MODIFIER_META;
+    }
+    if (mMetaState & AMETA_FUNCTION_ON) {
+        result |= MODIFIER_FN;
+    }
+    if (mMetaState & AMETA_CAPS_LOCK_ON) {
+        result |= MODIFIER_CAPSLOCK;
+    }
+    if (mMetaState & AMETA_NUM_LOCK_ON) {
+        result |= MODIFIER_NUMLOCK;
+    }
+    if (mMetaState & AMETA_SCROLL_LOCK_ON) {
+        result |= MODIFIER_SCROLLLOCK;
+    }
+    return result;
+}
+
 void
 AndroidPoint::Init(JNIEnv *jenv, jobject jobj)
 {
     if (jobj) {
         mX = jenv->GetIntField(jobj, jXField);
         mY = jenv->GetIntField(jobj, jYField);
     } else {
         mX = 0;
--- a/widget/android/AndroidJavaWrappers.h
+++ b/widget/android/AndroidJavaWrappers.h
@@ -337,22 +337,26 @@ enum {
     AKEYCODE_MUHENKAN           = 213,
     AKEYCODE_HENKAN             = 214,
     AKEYCODE_KATAKANA_HIRAGANA  = 215,
     AKEYCODE_YEN                = 216,
     AKEYCODE_RO                 = 217,
     AKEYCODE_KANA               = 218,
     AKEYCODE_ASSIST             = 219,
 
+    AMETA_FUNCTION_ON           = 0x00000008,
     AMETA_CTRL_ON               = 0x00001000,
     AMETA_CTRL_LEFT_ON          = 0x00002000,
     AMETA_CTRL_RIGHT_ON         = 0x00004000,
     AMETA_META_ON               = 0x00010000,
     AMETA_META_LEFT_ON          = 0x00020000,
     AMETA_META_RIGHT_ON         = 0x00040000,
+    AMETA_CAPS_LOCK_ON          = 0x00100000,
+    AMETA_NUM_LOCK_ON           = 0x00200000,
+    AMETA_SCROLL_LOCK_ON        = 0x00400000,
 
     AMETA_ALT_MASK              = AMETA_ALT_LEFT_ON   | AMETA_ALT_RIGHT_ON   | AMETA_ALT_ON,
     AMETA_CTRL_MASK             = AMETA_CTRL_LEFT_ON  | AMETA_CTRL_RIGHT_ON  | AMETA_CTRL_ON,
     AMETA_META_MASK             = AMETA_META_LEFT_ON  | AMETA_META_RIGHT_ON  | AMETA_META_ON,
     AMETA_SHIFT_MASK            = AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON | AMETA_SHIFT_ON,
 };
 
 class nsAndroidDisplayport MOZ_FINAL : public nsIAndroidDisplayport
@@ -499,16 +503,17 @@ public:
     double Z() { return mZ; }
     const nsIntRect& Rect() { return mRect; }
     nsAString& Characters() { return mCharacters; }
     nsAString& CharactersExtra() { return mCharactersExtra; }
     nsAString& Data() { return mData; }
     int KeyCode() { return mKeyCode; }
     int MetaState() { return mMetaState; }
     uint32_t DomKeyLocation() { return mDomKeyLocation; }
+    Modifiers DOMModifiers() const;
     bool IsAltPressed() const { return (mMetaState & AMETA_ALT_MASK) != 0; }
     bool IsShiftPressed() const { return (mMetaState & AMETA_SHIFT_MASK) != 0; }
     bool IsCtrlPressed() const { return (mMetaState & AMETA_CTRL_MASK) != 0; }
     bool IsMetaPressed() const { return (mMetaState & AMETA_META_MASK) != 0; }
     int Flags() { return mFlags; }
     int UnicodeChar() { return mUnicodeChar; }
     int BaseUnicodeChar() { return mBaseUnicodeChar; }
     int DOMPrintableKeyValue() { return mDOMPrintableKeyValue; }
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -1258,17 +1258,17 @@ nsWindow::DispatchGestureEvent(uint32_t 
 
 
 void
 nsWindow::DispatchMotionEvent(WidgetInputEvent &event, AndroidGeckoEvent *ae,
                               const nsIntPoint &refPoint)
 {
     nsIntPoint offset = WidgetToScreenOffset();
 
-    event.modifiers = 0;
+    event.modifiers = ae->DOMModifiers();
     event.time = ae->Time();
 
     // XXX possibly bound the range of event.refPoint here.
     //     some code may get confused.
     event.refPoint = LayoutDeviceIntPoint::FromUntyped(refPoint - offset);
 
     DispatchEvent(&event);
 }
@@ -1604,26 +1604,29 @@ nsWindow::InitKeyEvent(WidgetKeyboardEve
         InitPluginEvent(pluginEvent, action, key);
 
         event.isChar = false;
         event.charCode = 0;
         event.keyCode = domKeyCode;
         event.pluginEvent = pluginEvent;
     }
 
-    if (event.message != NS_KEY_PRESS ||
-        !key.UnicodeChar() || !key.BaseUnicodeChar() ||
-        key.UnicodeChar() == key.BaseUnicodeChar()) {
-        // For keypress, if the unicode char already has modifiers applied, we
-        // don't specify extra modifiers. If UnicodeChar() != BaseUnicodeChar()
-        // it means UnicodeChar() already has modifiers applied.
-        event.InitBasicModifiers(gMenu || key.IsCtrlPressed(),
-                                 key.IsAltPressed(),
-                                 key.IsShiftPressed(),
-                                 key.IsMetaPressed());
+    event.modifiers = key.DOMModifiers();
+    if (gMenu) {
+        event.modifiers |= MODIFIER_CONTROL;
+    }
+    // For keypress, if the unicode char already has modifiers applied, we
+    // don't specify extra modifiers. If UnicodeChar() != BaseUnicodeChar()
+    // it means UnicodeChar() already has modifiers applied.
+    // Note that on Android 4.x, Alt modifier isn't set when the key input
+    // causes text input even while right Alt key is pressed.  However, this
+    // is necessary for Android 2.3 compatibility.
+    if (event.message == NS_KEY_PRESS &&
+        key.UnicodeChar() && key.UnicodeChar() != key.BaseUnicodeChar()) {
+        event.modifiers &= ~(MODIFIER_ALT | MODIFIER_CONTROL | MODIFIER_META);
     }
 
     event.mIsRepeat =
         (event.message == NS_KEY_DOWN || event.message == NS_KEY_PRESS) &&
         (!!(key.Flags() & AKEY_EVENT_FLAG_LONG_PRESS) || !!key.RepeatCount());
     event.location = key.DomKeyLocation();
     event.time = key.Time();
 
--- a/widget/cocoa/TextInputHandler.h
+++ b/widget/cocoa/TextInputHandler.h
@@ -89,16 +89,22 @@ public:
    *
    * @param aLayoutID             An ID of keyboard layout.
    *                                0: US
    *                                1: Greek
    *                                2: German
    *                                3: Swedish-Pro
    *                                4: Dvorak-Qwerty Cmd
    *                                5: Thai
+   *                                6: Arabic
+   *                                7: French
+   *                                8: Hebrew
+   *                                9: Lithuanian
+   *                               10: Norwegian
+   *                               11: Spanish
    * @param aOverrideKeyboard     When testing set to TRUE, otherwise, set to
    *                              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();
--- a/widget/cocoa/TextInputHandler.mm
+++ b/widget/cocoa/TextInputHandler.mm
@@ -522,16 +522,34 @@ TISInputSourceWrapper::InitByLayoutID(SI
       InitByInputSourceID("com.apple.keylayout.Swedish-Pro");
       break;
     case 4:
       InitByInputSourceID("com.apple.keylayout.DVORAK-QWERTYCMD");
       break;
     case 5:
       InitByInputSourceID("com.apple.keylayout.Thai");
       break;
+    case 6:
+      InitByInputSourceID("com.apple.keylayout.Arabic");
+      break;
+    case 7:
+      InitByInputSourceID("com.apple.keylayout.French");
+      break;
+    case 8:
+      InitByInputSourceID("com.apple.keylayout.Hebrew");
+      break;
+    case 9:
+      InitByInputSourceID("com.apple.keylayout.Lithuanian");
+      break;
+    case 10:
+      InitByInputSourceID("com.apple.keylayout.Norwegian");
+      break;
+    case 11:
+      InitByInputSourceID("com.apple.keylayout.Spanish");
+      break;
     default:
       Clear();
       break;
   }
   mOverrideKeyboard = aOverrideKeyboard;
 }
 
 void
--- a/widget/tests/test_bug428405.xul
+++ b/widget/tests/test_bug428405.xul
@@ -21,33 +21,29 @@
       <browser onload="configureSecondTab();" id="tab2browser" flex="100%"/>
     </tabpanels>
   </tabbox>
 
   <script type="application/javascript"><![CDATA[
 
     SimpleTest.waitForExplicitFinish();
 
-    var gUtils;
-
     var gCmdOptYReceived = false;
 
     // Look for a cmd-opt-y event.
     function onKeyPress(aEvent) {
       gCmdOptYReceived = false;
       if (String.fromCharCode(aEvent.charCode) != 'y')
         return;
       if (aEvent.ctrlKey || aEvent.shiftKey || !aEvent.metaKey || !aEvent.altKey)
         return;
       gCmdOptYReceived = true;
     }
 
     function setGlobals() {
-      gUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                      getInterface(Components.interfaces.nsIDOMWindowUtils);
       var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].
                           getService(Components.interfaces.nsIWindowMediator);
       gChromeWindow = wm.getMostRecentWindow("navigator:browser");
       // For some reason, a global <key> element's oncommand handler only gets
       // invoked if the focus is outside both of the <browser> elements
       // (tab1browser and tab2browser).  So, to make sure we can see a
       // cmd-opt-y event in window1 (if one is available), regardless of where
       // the focus is in this window, we need to add a "keypress" event
@@ -142,21 +138,21 @@
     // latter make this test succeed when it should fail.
 
     // The 'aNativeKeyCode', 'aCharacters' and 'aUnmodifiedCharacters'
     // parameters used below (in synthesizeNativeReturnKey() and
     // synthesizeNativeCmdOptY()) were confirmed accurate using the
     // DebugEventsPlugin v1.01 from bmo bug 441880.
 
     function synthesizeNativeReturnKey() {
-      gUtils.sendNativeKeyEvent(0, MAC_VK_Return, 0, "\u000a", "\u000a");
+      synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, MAC_VK_Return, {}, "\u000a", "\u000a");
     }
 
     function synthesizeNativeCmdOptY() {
-      gUtils.sendNativeKeyEvent(0, MAC_VK_ANSI_Y, 0x5000, "y", "y");
+      synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, MAC_VK_ANSI_Y, {metaKey:1, altKey:1}, "y", "y");
     }
 
   ]]></script>
 
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml">
     <p id="display"></p>
     <div id="content" style="display: none"></div>
--- a/widget/tests/test_key_event_counts.xul
+++ b/widget/tests/test_key_event_counts.xul
@@ -26,33 +26,30 @@
     function onKeyPress(e)
     {
       gKeyPressEventCount++;
       e.preventDefault();
     }
 
     function runTest()
     {
-      var domWindowUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                             getInterface(Components.interfaces.nsIDOMWindowUtils);
-
       window.addEventListener("keypress", onKeyPress, false);
 
       // Test ctrl-tab
       gKeyPressEventCount = 0;
-      domWindowUtils.sendNativeKeyEvent(0, MAC_VK_Tab, 0x0400, "\t", "\t");
+      synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, MAC_VK_Tab, {ctrlKey:1}, "\t", "\t");
       is(gKeyPressEventCount, 1);
 
       // Test cmd+shift+a
       gKeyPressEventCount = 0;
-      domWindowUtils.sendNativeKeyEvent(0, MAC_VK_ANSI_A, 0x4000 | 0x0100, "a", "A");
+      synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, MAC_VK_ANSI_A, {metaKey:1, shiftKey:1}, "a", "A");
       is(gKeyPressEventCount, 1);
 
       // Test cmd-;
       gKeyPressEventCount = 0;
-      domWindowUtils.sendNativeKeyEvent(0, MAC_VK_ANSI_Semicolon, 0x4000, ";", ";");
+      synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, MAC_VK_ANSI_Semicolon, {metaKey:1}, ";", ";");
       is(gKeyPressEventCount, 1);
 
       window.removeEventListener("keypress", onKeyPress, false);
     }
   ]]></script>
 
 </window>
--- a/widget/tests/test_keycodes.xul
+++ b/widget/tests/test_keycodes.xul
@@ -7,16 +7,18 @@
   xmlns:html="http://www.w3.org/1999/xhtml"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <title>Key event tests</title>
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/NativeKeyCodes.js" />
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" />
 
 <keyset>
   <key id="unshiftedKey" key=";" modifiers="accel" oncommand="this.activeCount++"/>
   <key id="shiftedKey" key=":" modifiers="accel" oncommand="this.activeCount++"/>
   <key id="commandOptionF" key='f' modifiers="accel,alt" oncommand="this.activeCount++"/>
   <key id="question" key='?' modifiers="accel" oncommand="this.activeCount++"/>
   <key id="unshiftedX" key="x" modifiers="accel" oncommand="this.activeCount++"/>
   <key id="shiftedX" key="X" modifiers="accel,shift" oncommand="this.activeCount++"/>
@@ -56,126 +58,60 @@ function clearInfobars()
                   .QueryInterface(Ci.nsIDocShell).chromeEventHandler;
   var chromeWin = browser.ownerDocument.defaultView;
   var nb = chromeWin.gBrowser.getNotificationBox(browser);
   for (let n of nb.allNotifications) {
     nb.removeNotification(n, true);
   }
 }
 
-function synthesizeNativeKey(aLayout, aKeyCode, aModifiers, aSystemChars,
-                             aSystemUnmodifiedChars, aWindow)
-{
-  if (!aWindow)
-    aWindow = window;
-
-  var utils = aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                      getInterface(Components.interfaces.nsIDOMWindowUtils);
-
-  if (utils) {
-    var modifiers = 0;
-    if (aModifiers.capsLock) modifiers |= 0x01;
-    if (aModifiers.numLock) modifiers |= 0x02;
-    if (aModifiers.shift) modifiers |= 0x0100;
-    if (aModifiers.shiftRight) modifiers |= 0x0200;
-    if (aModifiers.ctrl) modifiers |= 0x0400;
-    if (aModifiers.ctrlRight) modifiers |= 0x0800;
-    if (aModifiers.alt) modifiers |= 0x1000;
-    if (aModifiers.altRight) modifiers |= 0x2000;
-    if (IS_WIN && aModifiers.altGr) {
-      if (!aModifiers.ctrl && !aModifiers.ctrlRight) {
-        modifiers |= 0x0400;
-      }
-      if (!aModifiers.alt && !aModifiers.altRight) {
-        modifiers |= 0x1000;
-      }
-    }
-    if (aModifiers.command) modifiers |= 0x4000;
-    if (aModifiers.commandRight) modifiers |= 0x8000;
-    if (aModifiers.help) modifiers |= 0x10000;
-    if (aModifiers.function) modifiers |= 0x100000;
-    if (aModifiers.numericKeyPad) modifiers |= 0x01000000;
-
-    utils.sendNativeKeyEvent(aLayout, aKeyCode, modifiers,
-                             aSystemChars, aSystemUnmodifiedChars);
-  }
-}
-
-var keyboardLayouts;
-if (IS_MAC) {
-  // Any unused number is okay for adding new keyboard layout.
-  // When you add new keyboard layout here, you need to modify
-  // TISInputSourceWrapper::InitByLayoutID().
-  keyboardLayouts = {
-    "US":              0,
-    "Greek":           1,
-    "German":          2,
-    "Swedish":         3,
-    "Dvorak-Qwerty":   4,
-    "Thai":            5
-  };
-} else if (IS_WIN) {
-  // These constants can be found by inspecting registry keys under
-  // HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Keyboard Layouts
-  keyboardLayouts = {
-    "US":0x409,
-    "German":0x407,
-    "Greek":0x408,
-    "Spanish":0x40a,
-    "French":0x40c,
-    "Swedish":0x41d,
-    "Arabic":0x401,
-    "Hebrew":0x40d,
-    "Japanese":0x411,
-    "Norwegian":0x414,
-    "BrazilianABNT":0x416,
-    "Lithuanian":0x10427,
-    "Thai": 0x2041e
-  };
-}
-
 function eventToString(aEvent)
 {
-  var name = aEvent.layout + " keyCode=" +
+  var name = aEvent.layout.name + " keyCode=" +
     aEvent.keyCode + " (0x" + aEvent.keyCode.toString(16).toUpperCase() +
       ") chars='" + aEvent.chars + "'";
-  if (aEvent.shift) {
+  if (typeof aEvent.unmodifiedChars === "string") {
+    name += " unmodifiedChars='" + aEvent.unmodifiedChars + "'";
+  }
+  if (aEvent.modifiers.shiftKey) {
     name += " [Shift]";
   }
-  if (aEvent.shiftRight) {
+  if (aEvent.modifiers.shiftRightKey) {
     name += " [Right Shift]";
   }
-  if (aEvent.ctrl) {
+  if (aEvent.modifiers.ctrlKey) {
     name += " [Ctrl]";
   }
-  if (aEvent.ctrlRight) {
+  if (aEvent.modifiers.ctrlRightKey) {
     name += " [Right Ctrl]";
   }
-  if (aEvent.alt) {
+  if (aEvent.modifiers.altKey) {
     name += " [Alt]";
   }
-  if (aEvent.altRight) {
+  if (aEvent.modifiers.altRightKey) {
     name += " [Right Alt]";
   }
-  if (aEvent.command) {
+  if (aEvent.modifiers.metaKey) {
     name += " [Command]";
   }
-  if (aEvent.commandRight) {
+  if (aEvent.modifiers.metaRightKey) {
     name += " [Right Command]";
   }
 
   return name;  
 }
 
 function synthesizeKey(aEvent, aFocusElementId)
 {
   document.getElementById(aFocusElementId).focus();
 
-  synthesizeNativeKey(keyboardLayouts[aEvent.layout],
-                      aEvent.keyCode, aEvent, aEvent.chars, aEvent.unmodifiedChars);
+  var sent = synthesizeNativeKey(aEvent.layout, aEvent.keyCode,
+                                 aEvent.modifiers,
+                                 aEvent.chars, aEvent.unmodifiedChars);
+  ok(sent, "synthesizeNativeKey() should send a native key event");
 }
 
 // Test the charcodes and modifiers being delivered to keypress handlers and
 // also keydown/keyup events too.
 function runKeyEventTests()
 {
   const nsIDOMKeyEvent = Components.interfaces.nsIDOMKeyEvent;
   var eventList, keyDownFlags, keyUpFlags, testingEvent, expectedDOMKeyCode;
@@ -211,47 +147,53 @@ function runKeyEventTests()
         flags = keyUpFlags;
       }
       switch (e.keyCode) {
         case e.DOM_VK_SHIFT:
           is(e.ctrlKey, (flags & kCtrlFlag) != 0, name + ", Ctrl of Shift " + e.type + " event mismatch");
           is(e.metaKey, (flags & kMetaFlag) != 0, name + ", Command of Shift " + e.type + " event mismatch");
           is(e.altKey, (flags & kAltFlag) != 0, name + ", Alt of Shift " + e.type + " event mismatch");
           is(e.shiftKey, e.type == "keydown", name + ", Shift of Shift " + e.type + " event mismatch");
-          return (testingEvent.shift || testingEvent.shiftRight) && removeFlag(e, kShiftFlag) && expectedDOMKeyCode != e.keyCode;
+          return (testingEvent.modifiers.shiftKey || testingEvent.modifiers.shiftRightKey) &&
+                 removeFlag(e, kShiftFlag) && expectedDOMKeyCode != e.keyCode;
         case e.DOM_VK_CONTROL:
           is(e.ctrlKey, e.type == "keydown", name + ", Ctrl of Ctrl " + e.type + " event mismatch");
           is(e.metaKey, (flags & kMetaFlag) != 0, name + ", Command of Ctrl " + e.type + " event mismatch");
           is(e.altKey, (flags & kAltFlag) != 0, name + ", Alt of Ctrl " + e.type + " event mismatch");
           is(e.shiftKey, (flags & kShiftFlag) != 0, name + ", Shift of Ctrl " + e.type + " event mismatch");
-          return (testingEvent.ctrl || testingEvent.ctrlRight || (IS_WIN && testingEvent.altGr)) && removeFlag(e, kCtrlFlag) && expectedDOMKeyCode != e.keyCode;
+          return (testingEvent.modifiers.ctrlKey || testingEvent.modifiers.ctrlRightKey || (IS_WIN && testingEvent.modifiers.altGrKey)) &&
+                 removeFlag(e, kCtrlFlag) && expectedDOMKeyCode != e.keyCode;
         case e.DOM_VK_ALT:
           is(e.ctrlKey, (flags & kCtrlFlag) != 0, name + ", Ctrl of Alt " + e.type + " event mismatch");
           is(e.metaKey, (flags & kMetaFlag) != 0, name + ", Command of Alt " + e.type + " event mismatch");
           is(e.altKey, e.type == "keydown", name + ", Alt of Alt " + e.type + " event mismatch");
           is(e.shiftKey, (flags & kShiftFlag) != 0, name + ", Shift of Alt " + e.type + " event mismatch");
-          return (testingEvent.alt || testingEvent.altRight || (IS_WIN && testingEvent.altGr)) && removeFlag(e, kAltFlag) && expectedDOMKeyCode != e.keyCode;
+          return (testingEvent.modifiers.altKey || testingEvent.modifiers.altRightKey || (IS_WIN && testingEvent.modifiers.altGrKey)) &&
+                 removeFlag(e, kAltFlag) && expectedDOMKeyCode != e.keyCode;
         case e.DOM_VK_META:
           is(e.ctrlKey, (flags & kCtrlFlag) != 0, name + ", Ctrl of Command " + e.type + " evnet mismatch");
           is(e.metaKey, e.type == "keydown", name + ", Command of Command " + e.type + " evnet mismatch");
           is(e.altKey, (flags & kAltFlag) != 0, name + ", Alt of Command " + e.type + " evnet mismatch");
           is(e.shiftKey, (flags & kShiftFlag) != 0, name + ", Shift of Command " + e.type + " evnet mismatch");
-          return testingEvent.command && removeFlag(e, kMetaFlag) && expectedDOMKeyCode != e.keyCode;
+          return (testingEvent.modifiers.metaKey || testingEvent.modifiers.metaRightKey) &&
+                 removeFlag(e, kMetaFlag) && expectedDOMKeyCode != e.keyCode;
         case e.DOM_VK_NUM_LOCK:
           is(e.ctrlKey, (flags & kCtrlFlag) != 0, name + ", Ctrl of NumLock " + e.type + " event mismatch");
           is(e.metaKey, (flags & kMetaFlag) != 0, name + ", Command of NumLock " + e.type + " event mismatch");
           is(e.altKey, (flags & kAltFlag) != 0, name + ", Alt of NumLock " + e.type + " event mismatch");
           is(e.shiftKey, (flags & kShiftFlag) != 0, name + ", Shift of NumLock " + e.type + " event mismatch");
-          return testingEvent.numLock && removeFlag(e, kNumLockFlag) && expectedDOMKeyCode != e.keyCode;
+          return (testingEvent.modifiers.numLockKey || testingEvent.modifiers.numericKeyPadKey) &&
+                 removeFlag(e, kNumLockFlag) && expectedDOMKeyCode != e.keyCode;
         case e.DOM_VK_CAPS_LOCK:
           is(e.ctrlKey, (flags & kCtrlFlag) != 0, name + ", Ctrl of CapsLock " + e.type + " event mismatch");
           is(e.metaKey, (flags & kMetaFlag) != 0, name + ", Command of CapsLock " + e.type + " event mismatch");
           is(e.altKey, (flags & kAltFlag) != 0, name + ", Alt of CapsLock " + e.type + " event mismatch");
           is(e.shiftKey, (flags & kShiftFlag) != 0, name + ", Shift of CapsLock " + e.type + " event mismatch");
-          return testingEvent.capsLock && removeFlag(e, kCapsLockFlag) && expectedDOMKeyCode != e.keyCode;
+          return testingEvent.modifiers.capsLockKey &&
+                 removeFlag(e, kCapsLockFlag) && expectedDOMKeyCode != e.keyCode;
       }
       return false;
     }
 
     // Ignore the state changing key events which is fired by the testing event.
     if (!isStateChangingModifierKeyEvent(e))
       eventList.push(e);
     if (e.type == "keypress") {
@@ -284,37 +226,46 @@ function runKeyEventTests()
     eventList = [];
 
     // The modifier key events which are fired for state changing are har to
     // test. We should ignore them for now.
     keyDownFlags = keyUpFlags = 0;
     if (!IS_MAC) {
       // On Mac, nsChildView doesn't generate modifier keydown/keyup events for
       // state changing for synthesizeNativeKeyEvent.
-      if (aEvent.shift || aEvent.shiftRight)
+      if (aEvent.modifiers.shiftKey || aEvent.modifiers.shiftRightKey) {
         keyDownFlags |= kShiftFlag;
-      if (aEvent.ctrl || aEvent.ctrlRight || (IS_WIN && aEvent.altGr))
+      }
+      if (aEvent.modifiers.ctrlKey || aEvent.modifiers.ctrlRightKey ||
+          (IS_WIN && aEvent.modifiers.altGrKey)) {
         keyDownFlags |= kCtrlFlag;
-      if (aEvent.alt || aEvent.altRight || (IS_WIN && aEvent.altGr))
+      }
+      if (aEvent.modifiers.altKey || aEvent.modifiers.altRightKey ||
+          (IS_WIN && aEvent.modifiers.altGrKey)) {
         keyDownFlags |= kAltFlag;
-      if (aEvent.command)
+      }
+      if (aEvent.modifiers.metaKey || aEvent.modifiers.metaRightKey) {
         keyDownFlags |= kMetaFlag;
-      if (aEvent.numLock)
+      }
+      if (aEvent.modifiers.numLockKey || aEvent.modifiers.numericKeyPadKey) {
         keyDownFlags |= kNumLockFlag;
-      if (aEvent.capsLock)
+      }
+      if (aEvent.modifiers.capsLockKey) {
         keyDownFlags |= kCapsLockFlag;
+      }
       keyUpFlags = keyDownFlags;
     }
 
     testingEvent = aEvent;
     expectedDOMKeyCode = aExpectedGeckoKeyCode;
 
-    synthesizeKey(aEvent, "button");
+    var name = eventToString(aEvent);
+    ok(true, "Starting: " + name);
 
-    var name = eventToString(aEvent);
+    synthesizeKey(aEvent, "button");
 
     var expectEventTypeList = [];
     if (aShouldDelivedEvent & SHOULD_DELIVER_KEYDOWN)
       expectEventTypeList.push("keydown");
     if (aShouldDelivedEvent & SHOULD_DELIVER_KEYPRESS) {
       expectEventTypeList.push("keypress");
       for (var i = 1; i < aExpectGeckoChar.length; i++) {
         expectEventTypeList.push("keypress");
@@ -332,26 +283,28 @@ function runKeyEventTests()
       if (firedEventType != "")
         is(firedEventType, expectEventType, name + ", wrong type event fired");
       else
         is(firedEventType, expectEventType, name + ", a needed event is not fired");
 
       if (firedEventType != "") {
         var e = eventList[i];
         if (e.type == "keypress") {
-          var isCtrlExpected = aEvent.ctrl || aEvent.ctrlRight || false;
-          var isAltExpected = aEvent.alt || aEvent.altRight || false;
-          if (IS_WIN && aEvent.altGr) {
+          var isCtrlExpected =
+            aEvent.modifiers.ctrlKey || aEvent.modifiers.ctrlRightKey || false;
+          var isAltExpected =
+            aEvent.modifiers.altKey || aEvent.modifiers.altRightKey || false;
+          if (IS_WIN && aEvent.modifiers.altGrKey) {
             isCtrlExpected = isAltExpected =
               ((aShouldDelivedEvent & SHOULD_NOT_CAUSE_INPUT) != 0);
           }
           is(e.ctrlKey, isCtrlExpected, name + ", Ctrl mismatch");
-          is(e.metaKey, aEvent.command || aEvent.commandRight || false, name + ", Command mismatch");
+          is(e.metaKey, aEvent.modifiers.metaKey || aEvent.modifiers.metaRightKey || false, name + ", Command mismatch");
           is(e.altKey, isAltExpected, name + ", Alt mismatch");
-          is(e.shiftKey, aEvent.shift || aEvent.shiftRight || false, name + ", Shift mismatch");
+          is(e.shiftKey, aEvent.modifiers.shiftKey || aEvent.modifiers.shiftRightKey || false, name + ", Shift mismatch");
         }
 
         if (aExpectGeckoChar.length > 0 && e.type == "keypress") {
           is(e.charCode, aExpectGeckoChar.charCodeAt(keypressCount++), name + ", charcode");
           if (aExpectedGeckoKeyCode >= 0) {
             if (aExpectGeckoChar) {
               is(e.keyCode, 0, name + ", wrong keycode");
             } else {
@@ -383,1743 +336,2561 @@ function runKeyEventTests()
     // preferences widget to enable other keyboard layouts and select them from the
     // input menu to see what keyboard events they generate.
     // Note that it's possible to send bogus key events here, e.g.
     // {keyCode:0, chars:"z", unmodifiedChars:"P"} --- sendNativeKeyEvent
     // makes no attempt to verify that the keyCode matches the characters. So only
     // test key event records that you saw Cocoa send.
 
     // Ctrl keys
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, ctrl:1, chars:"\u0001", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{ctrlKey:1}, chars:"\u0001", unmodifiedChars:"a"},
             nsIDOMKeyEvent.DOM_VK_A, "a", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, ctrl:1, shift:1, chars:"\u0001", unmodifiedChars:"A"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:"\u0001", unmodifiedChars:"A"},
             nsIDOMKeyEvent.DOM_VK_A, "A", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Alt keys
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, alt:1, chars:"\u00e5", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{altKey:1}, chars:"\u00e5", unmodifiedChars:"a"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00e5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, alt:1, shift:1, chars:"\u00c5", unmodifiedChars:"A"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{altKey:1, shiftKey:1}, chars:"\u00c5", unmodifiedChars:"A"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00c5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    
+
     // Command keys
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, command:1, chars:"a", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{metaKey:1}, chars:"a", unmodifiedChars:"a"},
             nsIDOMKeyEvent.DOM_VK_A, "a", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // Shift-cmd gives us the shifted character
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, command:1, shift:1, chars:"a", unmodifiedChars:"A"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{metaKey:1, shiftKey:1}, chars:"a", unmodifiedChars:"A"},
             nsIDOMKeyEvent.DOM_VK_A, "A", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // Ctrl-cmd gives us the unshifted character
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, command:1, ctrl:1, chars:"\u0001", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{metaKey:1, ctrlKey:1}, chars:"\u0001", unmodifiedChars:"a"},
             nsIDOMKeyEvent.DOM_VK_A, "a", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // Alt-cmd gives us the shifted character
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, command:1, alt:1, chars:"\u00e5", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{metaKey:1, altKey:1}, chars:"\u00e5", unmodifiedChars:"a"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00e5", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, command:1, alt:1, shift:1, chars:"\u00c5", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{metaKey:1, altKey:1, shiftKey:1}, chars:"\u00c5", unmodifiedChars:"a"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00c5", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Greek ctrl keys produce Latin charcodes
-    testKey({layout:"Greek", keyCode:MAC_VK_ANSI_A, ctrl:1, chars:"\u0001", unmodifiedChars:"\u03b1"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:MAC_VK_ANSI_A,
+             modifiers:{ctrlKey:1}, chars:"\u0001", unmodifiedChars:"\u03b1"},
             nsIDOMKeyEvent.DOM_VK_A, "a", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Greek", keyCode:MAC_VK_ANSI_A, ctrl:1, shift:1, chars:"\u0001", unmodifiedChars:"\u0391"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:MAC_VK_ANSI_A,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:"\u0001", unmodifiedChars:"\u0391"},
             nsIDOMKeyEvent.DOM_VK_A, "A", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Greek command keys
-    testKey({layout:"Greek", keyCode:MAC_VK_ANSI_A, command:1, chars:"a", unmodifiedChars:"\u03b1"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:MAC_VK_ANSI_A,
+             modifiers:{metaKey:1}, chars:"a", unmodifiedChars:"\u03b1"},
             nsIDOMKeyEvent.DOM_VK_A, "a", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // Shift-cmd gives us the shifted character
-    testKey({layout:"Greek", keyCode:MAC_VK_ANSI_A, command:1, shift:1, chars:"a", unmodifiedChars:"\u0391"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:MAC_VK_ANSI_A,
+             modifiers:{metaKey:1, shiftKey:1}, chars:"a", unmodifiedChars:"\u0391"},
             nsIDOMKeyEvent.DOM_VK_A, "A", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // Ctrl-cmd gives us the unshifted character
-    testKey({layout:"Greek", keyCode:MAC_VK_ANSI_A, command:1, ctrl:1, chars:"\u0001", unmodifiedChars:"\u03b1"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:MAC_VK_ANSI_A,
+             modifiers:{metaKey:1, ctrlKey:1}, chars:"\u0001", unmodifiedChars:"\u03b1"},
             nsIDOMKeyEvent.DOM_VK_A, "a", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // Alt-cmd gives us the shifted character
-    testKey({layout:"Greek", keyCode:MAC_VK_ANSI_A, command:1, alt:1, chars:"\u00a8", unmodifiedChars:"\u03b1"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:MAC_VK_ANSI_A,
+             modifiers:{metaKey:1, altKey:1}, chars:"\u00a8", unmodifiedChars:"\u03b1"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00a8", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Greek", keyCode:MAC_VK_ANSI_A, command:1, alt:1, shift:1, chars:"\u00b9", unmodifiedChars:"\u0391"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:MAC_VK_ANSI_A,
+             modifiers:{metaKey:1, altKey:1, shiftKey:1}, chars:"\u00b9", unmodifiedChars:"\u0391"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00b9", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // German
-    testKey({layout:"German", keyCode:MAC_VK_ANSI_A, chars:"a", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:MAC_VK_ANSI_A,
+             modifiers: {}, chars:"a", unmodifiedChars:"a"},
             nsIDOMKeyEvent.DOM_VK_A, "a", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"German", keyCode:MAC_VK_ANSI_LeftBracket, chars:"\u00fc", unmodifiedChars:"\u00fc"},
+    testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:MAC_VK_ANSI_LeftBracket,
+             modifiers: {}, chars:"\u00fc", unmodifiedChars:"\u00fc"},
             0, "\u00fc", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"German", keyCode:MAC_VK_ANSI_Minus, chars:"\u00df", unmodifiedChars:"\u00df"},
+    testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:MAC_VK_ANSI_Minus,
+             modifiers: {}, chars:"\u00df", unmodifiedChars:"\u00df"},
             nsIDOMKeyEvent.DOM_VK_QUESTION_MARK, "\u00df", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"German", keyCode:MAC_VK_ANSI_Minus, shift:1, chars:"?", unmodifiedChars:"?"},
+    testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:MAC_VK_ANSI_Minus,
+             modifiers:{shiftKey:1}, chars:"?", unmodifiedChars:"?"},
             nsIDOMKeyEvent.DOM_VK_QUESTION_MARK, "?", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // Note that Shift+SS is '?' but Cmd+Shift+SS is '/' on German layout.
     // Therefore, when Cmd key is pressed, the SS key's keycode is changed.
-    testKey({layout:"German", keyCode:MAC_VK_ANSI_Minus, command:1, chars:"\u00df", unmodifiedChars:"\u00df"},
+    testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:MAC_VK_ANSI_Minus,
+             modifiers:{metaKey:1}, chars:"\u00df", unmodifiedChars:"\u00df"},
             nsIDOMKeyEvent.DOM_VK_SLASH, "\u00df", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"German", keyCode:MAC_VK_ANSI_Minus, command:1, shift:1, chars:"/", unmodifiedChars:"?"},
+    testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:MAC_VK_ANSI_Minus,
+             modifiers:{metaKey:1, shiftKey:1}, chars:"/", unmodifiedChars:"?"},
             nsIDOMKeyEvent.DOM_VK_SLASH, "?", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Caps Lock key event
     // XXX keyup event of Caps Lock key is not fired.
-    testKey({layout:"US", keyCode:MAC_VK_CapsLock, capsLock:1, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_CapsLock,
+             modifiers:{capsLockKey:1}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_CAPS_LOCK, "", SHOULD_DELIVER_KEYDOWN, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_CapsLock, capsLock:0, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_CapsLock,
+             modifiers:{capsLockKey:0}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_CAPS_LOCK, "", SHOULD_DELIVER_KEYDOWN, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Shift/RightShift key event
-    testKey({layout:"US", keyCode:MAC_VK_Shift, shift:1, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_Shift,
+             modifiers:{shiftKey:1}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_SHIFT, "", SHOULD_DELIVER_KEYDOWN, KeyboardEvent.DOM_KEY_LOCATION_LEFT);
-    testKey({layout:"US", keyCode:MAC_VK_Shift, shift:0, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_Shift,
+             modifiers:{shiftKey:0}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_SHIFT, "", SHOULD_DELIVER_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_LEFT);
-    testKey({layout:"US", keyCode:MAC_VK_RightShift, shiftRight:1, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_RightShift,
+             modifiers:{shiftRightKey:1}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_SHIFT, "", SHOULD_DELIVER_KEYDOWN, KeyboardEvent.DOM_KEY_LOCATION_RIGHT);
-    testKey({layout:"US", keyCode:MAC_VK_RightShift, shiftRight:0, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_RightShift,
+             modifiers:{shiftRightKey:0}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_SHIFT, "", SHOULD_DELIVER_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_RIGHT);
 
     // Control/RightControl key event
-    testKey({layout:"US", keyCode:MAC_VK_Control, ctrl:1, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_Control,
+             modifiers:{ctrlKey:1}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_CONTROL, "", SHOULD_DELIVER_KEYDOWN, KeyboardEvent.DOM_KEY_LOCATION_LEFT);
-    testKey({layout:"US", keyCode:MAC_VK_Control, ctrl:0, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_Control,
+             modifiers:{ctrlKey:0}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_CONTROL, "", SHOULD_DELIVER_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_LEFT);
-    testKey({layout:"US", keyCode:MAC_VK_RightControl, ctrlRight:1, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_RightControl,
+             modifiers:{ctrlRightKey:1}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_CONTROL, "", SHOULD_DELIVER_KEYDOWN, KeyboardEvent.DOM_KEY_LOCATION_RIGHT);
-    testKey({layout:"US", keyCode:MAC_VK_RightControl, ctrlRight:0, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_RightControl,
+             modifiers:{ctrlRightKey:0}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_CONTROL, "", SHOULD_DELIVER_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_RIGHT);
 
     // Option/RightOption key event
-    testKey({layout:"US", keyCode:MAC_VK_Option, alt:1, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_Option,
+             modifiers:{altKey:1}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_ALT, "", SHOULD_DELIVER_KEYDOWN, KeyboardEvent.DOM_KEY_LOCATION_LEFT);
-    testKey({layout:"US", keyCode:MAC_VK_Option, alt:0, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_Option,
+             modifiers:{altKey:0}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_ALT, "", SHOULD_DELIVER_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_LEFT);
-    testKey({layout:"US", keyCode:MAC_VK_RightOption, altRight:1, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_RightOption,
+             modifiers:{altRightKey:1}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_ALT, "", SHOULD_DELIVER_KEYDOWN, KeyboardEvent.DOM_KEY_LOCATION_RIGHT);
-    testKey({layout:"US", keyCode:MAC_VK_RightOption, altRight:0, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_RightOption,
+             modifiers:{altRightKey:0}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_ALT, "", SHOULD_DELIVER_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_RIGHT);
 
     // Command/RightCommand key event
-    testKey({layout:"US", keyCode:MAC_VK_Command, command:1, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_Command,
+             modifiers:{metaKey:1}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_META, "", SHOULD_DELIVER_KEYDOWN, KeyboardEvent.DOM_KEY_LOCATION_LEFT);
-    testKey({layout:"US", keyCode:MAC_VK_Command, command:0, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_Command,
+             modifiers:{metaKey:0}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_META, "", SHOULD_DELIVER_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_LEFT);
-    testKey({layout:"US", keyCode:MAC_VK_RightCommand, commandRight:1, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_RightCommand,
+             modifiers:{metaRightKey:1}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_META, "", SHOULD_DELIVER_KEYDOWN, KeyboardEvent.DOM_KEY_LOCATION_RIGHT);
-    testKey({layout:"US", keyCode:MAC_VK_RightCommand, commandRight:0, chars:"", unmodifiedChars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_RightCommand,
+             modifiers:{metaRightKey:0}, chars:"", unmodifiedChars:""},
             nsIDOMKeyEvent.DOM_VK_META, "", SHOULD_DELIVER_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_RIGHT);
 
     // all keys on keyboard (keyCode test)
-    testKey({layout:"US", keyCode:MAC_VK_Tab, chars:"\t", unmodifiedChars:"\t"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_Tab,
+             modifiers: {}, chars:"\t", unmodifiedChars:"\t"},
             nsIDOMKeyEvent.DOM_VK_TAB, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadClear, chars:"\uF739", unmodifiedChars:"\uF739"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadClear,
+             modifiers: {}, chars:"\uF739", unmodifiedChars:"\uF739"},
             nsIDOMKeyEvent.DOM_VK_CLEAR, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_Return, chars:"\u000D", unmodifiedChars:"\u000D"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_Return,
+             modifiers: {}, chars:"\u000D", unmodifiedChars:"\u000D"},
             nsIDOMKeyEvent.DOM_VK_RETURN, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_F15, chars:"\uF712", unmodifiedChars:"\uF712"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_F15,
+             modifiers: {}, chars:"\uF712", unmodifiedChars:"\uF712"},
             nsIDOMKeyEvent.DOM_VK_PAUSE, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_Escape, chars:"\u001B", unmodifiedChars:"\u001B"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_Escape,
+             modifiers: {}, chars:"\u001B", unmodifiedChars:"\u001B"},
             nsIDOMKeyEvent.DOM_VK_ESCAPE, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_Space, chars:" ", unmodifiedChars:" "},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_Space,
+             modifiers: {}, chars:" ", unmodifiedChars:" "},
             nsIDOMKeyEvent.DOM_VK_SPACE, " ", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_PageUp, chars:"\uF72C", unmodifiedChars:"\uF72C"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_PageUp,
+             modifiers: {}, chars:"\uF72C", unmodifiedChars:"\uF72C"},
             nsIDOMKeyEvent.DOM_VK_PAGE_UP, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_PageDown, chars:"\uF72D", unmodifiedChars:"\uF72D"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_PageDown,
+             modifiers: {}, chars:"\uF72D", unmodifiedChars:"\uF72D"},
             nsIDOMKeyEvent.DOM_VK_PAGE_DOWN, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_End, chars:"\uF72B", unmodifiedChars:"\uF72B"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_End,
+             modifiers: {}, chars:"\uF72B", unmodifiedChars:"\uF72B"},
             nsIDOMKeyEvent.DOM_VK_END, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_Home, chars:"\uF729", unmodifiedChars:"\uF729"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_Home,
+             modifiers: {}, chars:"\uF729", unmodifiedChars:"\uF729"},
             nsIDOMKeyEvent.DOM_VK_HOME, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_LeftArrow, chars:"\uF702", unmodifiedChars:"\uF702"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_LeftArrow,
+             modifiers: {}, chars:"\uF702", unmodifiedChars:"\uF702"},
             nsIDOMKeyEvent.DOM_VK_LEFT, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_UpArrow, chars:"\uF700", unmodifiedChars:"\uF700"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_UpArrow,
+             modifiers: {}, chars:"\uF700", unmodifiedChars:"\uF700"},
             nsIDOMKeyEvent.DOM_VK_UP, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_RightArrow, chars:"\uF703", unmodifiedChars:"\uF703"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_RightArrow,
+             modifiers: {}, chars:"\uF703", unmodifiedChars:"\uF703"},
             nsIDOMKeyEvent.DOM_VK_RIGHT, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_DownArrow, chars:"\uF701", unmodifiedChars:"\uF701"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_DownArrow,
+             modifiers: {}, chars:"\uF701", unmodifiedChars:"\uF701"},
             nsIDOMKeyEvent.DOM_VK_DOWN, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_PC_PrintScreen, chars:"\uF710", unmodifiedChars:"\uF710"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_PC_PrintScreen,
+             modifiers: {}, chars:"\uF710", unmodifiedChars:"\uF710"},
             nsIDOMKeyEvent.DOM_VK_PRINTSCREEN, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_PC_Delete, chars:"\uF728", unmodifiedChars:"\uF728"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_PC_Delete,
+             modifiers: {}, chars:"\uF728", unmodifiedChars:"\uF728"},
             nsIDOMKeyEvent.DOM_VK_DELETE, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_PC_Pause, chars:"\uF711", unmodifiedChars:"\uF711"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_PC_Pause,
+             modifiers: {}, chars:"\uF711", unmodifiedChars:"\uF711"},
             nsIDOMKeyEvent.DOM_VK_SCROLL_LOCK, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_PC_ContextMenu, chars:"\u0010", unmodifiedChars:"\u0010"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_PC_ContextMenu,
+             modifiers: {}, chars:"\u0010", unmodifiedChars:"\u0010"},
             nsIDOMKeyEvent.DOM_VK_CONTEXT_MENU, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"US", keyCode:MAC_VK_F1, function:1, chars:"\uF704", unmodifiedChars:"\uF704"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_F1,
+             modifiers:{fnKey:1}, chars:"\uF704", unmodifiedChars:"\uF704"},
             nsIDOMKeyEvent.DOM_VK_F1, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_F2, function:1, chars:"\uF705", unmodifiedChars:"\uF705"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_F2,
+             modifiers:{fnKey:1}, chars:"\uF705", unmodifiedChars:"\uF705"},
             nsIDOMKeyEvent.DOM_VK_F2, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_F3, function:1, chars:"\uF706", unmodifiedChars:"\uF706"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_F3,
+             modifiers:{fnKey:1}, chars:"\uF706", unmodifiedChars:"\uF706"},
             nsIDOMKeyEvent.DOM_VK_F3, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_F4, function:1, chars:"\uF707", unmodifiedChars:"\uF707"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_F4,
+             modifiers:{fnKey:1}, chars:"\uF707", unmodifiedChars:"\uF707"},
             nsIDOMKeyEvent.DOM_VK_F4, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_F5, function:1, chars:"\uF708", unmodifiedChars:"\uF708"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_F5,
+             modifiers:{fnKey:1}, chars:"\uF708", unmodifiedChars:"\uF708"},
             nsIDOMKeyEvent.DOM_VK_F5, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_F6, function:1, chars:"\uF709", unmodifiedChars:"\uF709"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_F6,
+             modifiers:{fnKey:1}, chars:"\uF709", unmodifiedChars:"\uF709"},
             nsIDOMKeyEvent.DOM_VK_F6, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_F7, function:1, chars:"\uF70A", unmodifiedChars:"\uF70A"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_F7,
+             modifiers:{fnKey:1}, chars:"\uF70A", unmodifiedChars:"\uF70A"},
             nsIDOMKeyEvent.DOM_VK_F7, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_F8, function:1, chars:"\uF70B", unmodifiedChars:"\uF70B"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_F8,
+             modifiers:{fnKey:1}, chars:"\uF70B", unmodifiedChars:"\uF70B"},
             nsIDOMKeyEvent.DOM_VK_F8, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_F9, function:1, chars:"\uF70C", unmodifiedChars:"\uF70C"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_F9,
+             modifiers:{fnKey:1}, chars:"\uF70C", unmodifiedChars:"\uF70C"},
             nsIDOMKeyEvent.DOM_VK_F9, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_F10, function:1, chars:"\uF70D", unmodifiedChars:"\uF70D"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_F10,
+             modifiers:{fnKey:1}, chars:"\uF70D", unmodifiedChars:"\uF70D"},
             nsIDOMKeyEvent.DOM_VK_F10, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_F11, function:1, chars:"\uF70E", unmodifiedChars:"\uF70E"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_F11,
+             modifiers:{fnKey:1}, chars:"\uF70E", unmodifiedChars:"\uF70E"},
             nsIDOMKeyEvent.DOM_VK_F11, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_F12, function:1, chars:"\uF70F", unmodifiedChars:"\uF70F"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_F12,
+             modifiers:{fnKey:1}, chars:"\uF70F", unmodifiedChars:"\uF70F"},
             nsIDOMKeyEvent.DOM_VK_F12, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_F16, function:1, chars:"\uF713", unmodifiedChars:"\uF713"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_F16,
+             modifiers:{fnKey:1}, chars:"\uF713", unmodifiedChars:"\uF713"},
             nsIDOMKeyEvent.DOM_VK_F16, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_F17, function:1, chars:"\uF714", unmodifiedChars:"\uF714"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_F17,
+             modifiers:{fnKey:1}, chars:"\uF714", unmodifiedChars:"\uF714"},
             nsIDOMKeyEvent.DOM_VK_F17, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_F18, function:1, chars:"\uF715", unmodifiedChars:"\uF715"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_F18,
+             modifiers:{fnKey:1}, chars:"\uF715", unmodifiedChars:"\uF715"},
             nsIDOMKeyEvent.DOM_VK_F18, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_F19, function:1, chars:"\uF716", unmodifiedChars:"\uF716"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_F19,
+             modifiers:{fnKey:1}, chars:"\uF716", unmodifiedChars:"\uF716"},
             nsIDOMKeyEvent.DOM_VK_F19, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // US
     // Alphabet
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, chars:"a", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers: {}, chars:"a", unmodifiedChars:"a"},
             nsIDOMKeyEvent.DOM_VK_A, "a", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, shift:1, chars:"A", unmodifiedChars:"A"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{shiftKey:1}, chars:"A", unmodifiedChars:"A"},
             nsIDOMKeyEvent.DOM_VK_A, "A", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, ctrl:1, chars:"\u0001", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{ctrlKey:1}, chars:"\u0001", unmodifiedChars:"a"},
             nsIDOMKeyEvent.DOM_VK_A, "a", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, alt:1, chars:"\u00E5", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{altKey:1}, chars:"\u00E5", unmodifiedChars:"a"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00E5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, command:1, chars:"a", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{metaKey:1}, chars:"a", unmodifiedChars:"a"},
             nsIDOMKeyEvent.DOM_VK_A, "a", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_B, chars:"b", unmodifiedChars:"b"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_B,
+             modifiers:{}, chars:"b", unmodifiedChars:"b"},
             nsIDOMKeyEvent.DOM_VK_B, "b", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_B, shift:1, chars:"B", unmodifiedChars:"B"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_B,
+             modifiers:{shiftKey:1}, chars:"B", unmodifiedChars:"B"},
             nsIDOMKeyEvent.DOM_VK_B, "B", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_B, ctrl:1, chars:"\u0002", unmodifiedChars:"b"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_B,
+             modifiers:{ctrlKey:1}, chars:"\u0002", unmodifiedChars:"b"},
             nsIDOMKeyEvent.DOM_VK_B, "b", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_B, alt:1, chars:"\u222B", unmodifiedChars:"b"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_B,
+             modifiers:{altKey:1}, chars:"\u222B", unmodifiedChars:"b"},
             nsIDOMKeyEvent.DOM_VK_B, "\u222B", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_B, command:1, chars:"b", unmodifiedChars:"b"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_B,
+             modifiers:{metaKey:1}, chars:"b", unmodifiedChars:"b"},
             nsIDOMKeyEvent.DOM_VK_B, "b", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_C, chars:"c", unmodifiedChars:"c"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_C,
+             modifiers:{}, chars:"c", unmodifiedChars:"c"},
             nsIDOMKeyEvent.DOM_VK_C, "c", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_C, shift:1, chars:"C", unmodifiedChars:"C"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_C,
+             modifiers:{shiftKey:1}, chars:"C", unmodifiedChars:"C"},
             nsIDOMKeyEvent.DOM_VK_C, "C", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_C, ctrl:1, chars:"\u0003", unmodifiedChars:"c"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_C,
+             modifiers:{ctrlKey:1}, chars:"\u0003", unmodifiedChars:"c"},
             nsIDOMKeyEvent.DOM_VK_C, "c", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_C, alt:1, chars:"\u00E7", unmodifiedChars:"c"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_C,
+             modifiers:{altKey:1}, chars:"\u00E7", unmodifiedChars:"c"},
             nsIDOMKeyEvent.DOM_VK_C, "\u00E7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_C, command:1, chars:"c", unmodifiedChars:"c"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_C,
+             modifiers:{metaKey:1}, chars:"c", unmodifiedChars:"c"},
             nsIDOMKeyEvent.DOM_VK_C, "c", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_D, chars:"d", unmodifiedChars:"d"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_D,
+             modifiers:{}, chars:"d", unmodifiedChars:"d"},
             nsIDOMKeyEvent.DOM_VK_D, "d", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_D, shift:1, chars:"D", unmodifiedChars:"D"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_D,
+             modifiers:{shiftKey:1}, chars:"D", unmodifiedChars:"D"},
             nsIDOMKeyEvent.DOM_VK_D, "D", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_D, ctrl:1, chars:"\u0004", unmodifiedChars:"d"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_D,
+             modifiers:{ctrlKey:1}, chars:"\u0004", unmodifiedChars:"d"},
             nsIDOMKeyEvent.DOM_VK_D, "d", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_D, alt:1, chars:"\u2202", unmodifiedChars:"d"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_D,
+             modifiers:{altKey:1}, chars:"\u2202", unmodifiedChars:"d"},
             nsIDOMKeyEvent.DOM_VK_D, "\u2202", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_D, command:1, chars:"d", unmodifiedChars:"d"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_D,
+             modifiers:{metaKey:1}, chars:"d", unmodifiedChars:"d"},
             nsIDOMKeyEvent.DOM_VK_D, "d", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_E, chars:"e", unmodifiedChars:"e"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_E,
+             modifiers:{}, chars:"e", unmodifiedChars:"e"},
             nsIDOMKeyEvent.DOM_VK_E, "e", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_E, shift:1, chars:"E", unmodifiedChars:"E"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_E,
+             modifiers:{shiftKey:1}, chars:"E", unmodifiedChars:"E"},
             nsIDOMKeyEvent.DOM_VK_E, "E", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_E, ctrl:1, chars:"\u0005", unmodifiedChars:"e"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_E,
+             modifiers:{ctrlKey:1}, chars:"\u0005", unmodifiedChars:"e"},
             nsIDOMKeyEvent.DOM_VK_E, "e", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_E, alt:1, chars:"", unmodifiedChars:"e"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_E,
+             modifiers:{altKey:1}, chars:"", unmodifiedChars:"e"},
             nsIDOMKeyEvent.DOM_VK_E, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // dead key
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_E, command:1, chars:"e", unmodifiedChars:"e"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_E,
+             modifiers:{metaKey:1}, chars:"e", unmodifiedChars:"e"},
             nsIDOMKeyEvent.DOM_VK_E, "e", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_F, chars:"f", unmodifiedChars:"f"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_F,
+             modifiers:{}, chars:"f", unmodifiedChars:"f"},
             nsIDOMKeyEvent.DOM_VK_F, "f", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_F, shift:1, chars:"F", unmodifiedChars:"F"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_F,
+             modifiers:{shiftKey:1}, chars:"F", unmodifiedChars:"F"},
             nsIDOMKeyEvent.DOM_VK_F, "F", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_F, ctrl:1, chars:"\u0006", unmodifiedChars:"f"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_F,
+             modifiers:{ctrlKey:1}, chars:"\u0006", unmodifiedChars:"f"},
             nsIDOMKeyEvent.DOM_VK_F, "f", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_F, alt:1, chars:"\u0192", unmodifiedChars:"f"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_F,
+             modifiers:{altKey:1}, chars:"\u0192", unmodifiedChars:"f"},
             nsIDOMKeyEvent.DOM_VK_F, "\u0192", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // XXX This test starts fullscreen mode.
-    // testKey({layout:"US", keyCode:MAC_VK_ANSI_F, command:1, chars:"f", unmodifiedChars:"f"},
+    // testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_F,
+    //          modifiers:{metaKey:1}, chars:"f", unmodifiedChars:"f"},
     //         nsIDOMKeyEvent.DOM_VK_F, "f", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_G, chars:"g", unmodifiedChars:"g"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_G,
+             modifiers:{}, chars:"g", unmodifiedChars:"g"},
             nsIDOMKeyEvent.DOM_VK_G, "g", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_G, shift:1, chars:"G", unmodifiedChars:"G"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_G,
+             modifiers:{shiftKey:1}, chars:"G", unmodifiedChars:"G"},
             nsIDOMKeyEvent.DOM_VK_G, "G", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_G, ctrl:1, chars:"\u0007", unmodifiedChars:"g"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_G,
+             modifiers:{ctrlKey:1}, chars:"\u0007", unmodifiedChars:"g"},
             nsIDOMKeyEvent.DOM_VK_G, "g", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_G, alt:1, chars:"\u00A9", unmodifiedChars:"g"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_G,
+             modifiers:{altKey:1}, chars:"\u00A9", unmodifiedChars:"g"},
             nsIDOMKeyEvent.DOM_VK_G, "\u00A9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_G, command:1, chars:"g", unmodifiedChars:"g"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_G,
+             modifiers:{metaKey:1}, chars:"g", unmodifiedChars:"g"},
             nsIDOMKeyEvent.DOM_VK_G, "g", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_H, chars:"h", unmodifiedChars:"h"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_H,
+             modifiers:{}, chars:"h", unmodifiedChars:"h"},
             nsIDOMKeyEvent.DOM_VK_H, "h", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_H, shift:1, chars:"H", unmodifiedChars:"H"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_H,
+             modifiers:{shiftKey:1}, chars:"H", unmodifiedChars:"H"},
             nsIDOMKeyEvent.DOM_VK_H, "H", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_H, ctrl:1, chars:"\u0008", unmodifiedChars:"h"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_H,
+             modifiers:{ctrlKey:1}, chars:"\u0008", unmodifiedChars:"h"},
             nsIDOMKeyEvent.DOM_VK_H, "h", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_H, alt:1, chars:"\u02D9", unmodifiedChars:"h"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_H,
+             modifiers:{altKey:1}, chars:"\u02D9", unmodifiedChars:"h"},
             nsIDOMKeyEvent.DOM_VK_H, "\u02D9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_H, command:1, chars:"h", unmodifiedChars:"h"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_H,
+             modifiers:{metaKey:1}, chars:"h", unmodifiedChars:"h"},
             nsIDOMKeyEvent.DOM_VK_H, "h", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_I, chars:"i", unmodifiedChars:"i"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_I,
+             modifiers:{}, chars:"i", unmodifiedChars:"i"},
             nsIDOMKeyEvent.DOM_VK_I, "i", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_I, shift:1, chars:"I", unmodifiedChars:"I"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_I,
+             modifiers:{shiftKey:1}, chars:"I", unmodifiedChars:"I"},
             nsIDOMKeyEvent.DOM_VK_I, "I", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_I, ctrl:1, chars:"\u0009", unmodifiedChars:"i"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_I,
+             modifiers:{ctrlKey:1}, chars:"\u0009", unmodifiedChars:"i"},
             nsIDOMKeyEvent.DOM_VK_I, "i", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_I, alt:1, chars:"", unmodifiedChars:"i"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_I,
+             modifiers:{altKey:1}, chars:"", unmodifiedChars:"i"},
             nsIDOMKeyEvent.DOM_VK_I, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // dead key
     // XXX This test causes memory leak.
-    // testKey({layout:"US", keyCode:MAC_VK_ANSI_I, command:1, chars:"i", unmodifiedChars:"i"},
+    // testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_I,
+    //          modifiers:{metaKey:1}, chars:"i", unmodifiedChars:"i"},
     //         nsIDOMKeyEvent.DOM_VK_I, "i", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_J, chars:"j", unmodifiedChars:"j"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_J,
+             modifiers:{}, chars:"j", unmodifiedChars:"j"},
             nsIDOMKeyEvent.DOM_VK_J, "j", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_J, shift:1, chars:"J", unmodifiedChars:"J"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_J,
+             modifiers:{shiftKey:1}, chars:"J", unmodifiedChars:"J"},
             nsIDOMKeyEvent.DOM_VK_J, "J", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_J, ctrl:1, chars:"\u000A", unmodifiedChars:"j"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_J,
+             modifiers:{ctrlKey:1}, chars:"\u000A", unmodifiedChars:"j"},
             nsIDOMKeyEvent.DOM_VK_J, "j", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_J, alt:1, chars:"\u2206", unmodifiedChars:"j"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_J,
+             modifiers:{altKey:1}, chars:"\u2206", unmodifiedChars:"j"},
             nsIDOMKeyEvent.DOM_VK_J, "\u2206", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_J, command:1, chars:"j", unmodifiedChars:"j"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_J,
+             modifiers:{metaKey:1}, chars:"j", unmodifiedChars:"j"},
             nsIDOMKeyEvent.DOM_VK_J, "j", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_K, chars:"k", unmodifiedChars:"k"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_K,
+             modifiers:{}, chars:"k", unmodifiedChars:"k"},
             nsIDOMKeyEvent.DOM_VK_K, "k", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_K, shift:1, chars:"K", unmodifiedChars:"K"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_K,
+             modifiers:{shiftKey:1}, chars:"K", unmodifiedChars:"K"},
             nsIDOMKeyEvent.DOM_VK_K, "K", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_K, ctrl:1, chars:"\u000B", unmodifiedChars:"k"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_K,
+             modifiers:{ctrlKey:1}, chars:"\u000B", unmodifiedChars:"k"},
             nsIDOMKeyEvent.DOM_VK_K, "k", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_K, alt:1, chars:"\u02DA", unmodifiedChars:"k"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_K,
+             modifiers:{altKey:1}, chars:"\u02DA", unmodifiedChars:"k"},
             nsIDOMKeyEvent.DOM_VK_K, "\u02DA", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_K, command:1, chars:"k", unmodifiedChars:"k"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_K,
+             modifiers:{metaKey:1}, chars:"k", unmodifiedChars:"k"},
             nsIDOMKeyEvent.DOM_VK_K, "k", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_L, chars:"l", unmodifiedChars:"l"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_L,
+             modifiers:{}, chars:"l", unmodifiedChars:"l"},
             nsIDOMKeyEvent.DOM_VK_L, "l", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_L, shift:1, chars:"L", unmodifiedChars:"L"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_L,
+             modifiers:{shiftKey:1}, chars:"L", unmodifiedChars:"L"},
             nsIDOMKeyEvent.DOM_VK_L, "L", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_L, ctrl:1, chars:"\u000C", unmodifiedChars:"l"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_L,
+             modifiers:{ctrlKey:1}, chars:"\u000C", unmodifiedChars:"l"},
             nsIDOMKeyEvent.DOM_VK_L, "l", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_L, alt:1, chars:"\u00AC", unmodifiedChars:"l"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_L,
+             modifiers:{altKey:1}, chars:"\u00AC", unmodifiedChars:"l"},
             nsIDOMKeyEvent.DOM_VK_L, "\u00AC", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_L, command:1, chars:"l", unmodifiedChars:"l"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_L,
+             modifiers:{metaKey:1}, chars:"l", unmodifiedChars:"l"},
             nsIDOMKeyEvent.DOM_VK_L, "l", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_M, chars:"m", unmodifiedChars:"m"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_M,
+             modifiers:{}, chars:"m", unmodifiedChars:"m"},
             nsIDOMKeyEvent.DOM_VK_M, "m", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_M, shift:1, chars:"M", unmodifiedChars:"M"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_M,
+             modifiers:{shiftKey:1}, chars:"M", unmodifiedChars:"M"},
             nsIDOMKeyEvent.DOM_VK_M, "M", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_M, ctrl:1, chars:"\u000D", unmodifiedChars:"m"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_M,
+             modifiers:{ctrlKey:1}, chars:"\u000D", unmodifiedChars:"m"},
             nsIDOMKeyEvent.DOM_VK_M, "m", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_M, alt:1, chars:"\u00B5", unmodifiedChars:"m"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_M,
+             modifiers:{altKey:1}, chars:"\u00B5", unmodifiedChars:"m"},
             nsIDOMKeyEvent.DOM_VK_M, "\u00B5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_M, command:1, chars:"m", unmodifiedChars:"m"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_M,
+             modifiers:{metaKey:1}, chars:"m", unmodifiedChars:"m"},
             nsIDOMKeyEvent.DOM_VK_M, "m", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_N, chars:"n", unmodifiedChars:"n"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_N,
+             modifiers:{}, chars:"n", unmodifiedChars:"n"},
             nsIDOMKeyEvent.DOM_VK_N, "n", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_N, shift:1, chars:"N", unmodifiedChars:"N"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_N,
+             modifiers:{shiftKey:1}, chars:"N", unmodifiedChars:"N"},
             nsIDOMKeyEvent.DOM_VK_N, "N", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_N, ctrl:1, chars:"\u000E", unmodifiedChars:"n"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_N,
+             modifiers:{ctrlKey:1}, chars:"\u000E", unmodifiedChars:"n"},
             nsIDOMKeyEvent.DOM_VK_N, "n", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_N, alt:1, chars:"", unmodifiedChars:"n"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_N,
+             modifiers:{altKey:1}, chars:"", unmodifiedChars:"n"},
             nsIDOMKeyEvent.DOM_VK_N, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // dead key
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_N, command:1, chars:"n", unmodifiedChars:"n"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_N,
+             modifiers:{metaKey:1}, chars:"n", unmodifiedChars:"n"},
             nsIDOMKeyEvent.DOM_VK_N, "n", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_O, chars:"o", unmodifiedChars:"o"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_O,
+             modifiers:{}, chars:"o", unmodifiedChars:"o"},
             nsIDOMKeyEvent.DOM_VK_O, "o", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_O, shift:1, chars:"O", unmodifiedChars:"O"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_O,
+             modifiers:{shiftKey:1}, chars:"O", unmodifiedChars:"O"},
             nsIDOMKeyEvent.DOM_VK_O, "O", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_O, ctrl:1, chars:"\u000F", unmodifiedChars:"o"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_O,
+             modifiers:{ctrlKey:1}, chars:"\u000F", unmodifiedChars:"o"},
             nsIDOMKeyEvent.DOM_VK_O, "o", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_O, alt:1, chars:"\u00F8", unmodifiedChars:"o"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_O,
+             modifiers:{altKey:1}, chars:"\u00F8", unmodifiedChars:"o"},
             nsIDOMKeyEvent.DOM_VK_O, "\u00F8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_O, command:1, chars:"o", unmodifiedChars:"o"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_O,
+             modifiers:{metaKey:1}, chars:"o", unmodifiedChars:"o"},
             nsIDOMKeyEvent.DOM_VK_O, "o", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_P, chars:"p", unmodifiedChars:"p"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_P,
+             modifiers:{}, chars:"p", unmodifiedChars:"p"},
             nsIDOMKeyEvent.DOM_VK_P, "p", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_P, shift:1, chars:"P", unmodifiedChars:"P"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_P,
+             modifiers:{shiftKey:1}, chars:"P", unmodifiedChars:"P"},
             nsIDOMKeyEvent.DOM_VK_P, "P", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_P, ctrl:1, chars:"\u0010", unmodifiedChars:"p"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_P,
+             modifiers:{ctrlKey:1}, chars:"\u0010", unmodifiedChars:"p"},
             nsIDOMKeyEvent.DOM_VK_P, "p", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_P, alt:1, chars:"\u03C0", unmodifiedChars:"p"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_P,
+             modifiers:{altKey:1}, chars:"\u03C0", unmodifiedChars:"p"},
             nsIDOMKeyEvent.DOM_VK_P, "\u03C0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // XXX This test starts private browsing mode (stopped at the confirmation dialog)
-    // testKey({layout:"US", keyCode:MAC_VK_ANSI_P, command:1, chars:"p", unmodifiedChars:"p"},
+    // testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_P,
+    //          modifiers:{metaKey:1}, chars:"p", unmodifiedChars:"p"},
     //         nsIDOMKeyEvent.DOM_VK_P, "p", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Q, chars:"q", unmodifiedChars:"q"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Q,
+             modifiers:{}, chars:"q", unmodifiedChars:"q"},
             nsIDOMKeyEvent.DOM_VK_Q, "q", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Q, shift:1, chars:"Q", unmodifiedChars:"Q"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Q,
+             modifiers:{shiftKey:1}, chars:"Q", unmodifiedChars:"Q"},
             nsIDOMKeyEvent.DOM_VK_Q, "Q", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Q, ctrl:1, chars:"\u0011", unmodifiedChars:"q"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Q,
+             modifiers:{ctrlKey:1}, chars:"\u0011", unmodifiedChars:"q"},
             nsIDOMKeyEvent.DOM_VK_Q, "q", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Q, alt:1, chars:"\u0153", unmodifiedChars:"q"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Q,
+             modifiers:{altKey:1}, chars:"\u0153", unmodifiedChars:"q"},
             nsIDOMKeyEvent.DOM_VK_Q, "\u0153", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Q, command:1, chars:"q", unmodifiedChars:"q"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Q,
+             modifiers:{metaKey:1}, chars:"q", unmodifiedChars:"q"},
             nsIDOMKeyEvent.DOM_VK_Q, "q", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_R, chars:"r", unmodifiedChars:"r"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_R,
+             modifiers:{}, chars:"r", unmodifiedChars:"r"},
             nsIDOMKeyEvent.DOM_VK_R, "r", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_R, shift:1, chars:"R", unmodifiedChars:"R"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_R,
+             modifiers:{shiftKey:1}, chars:"R", unmodifiedChars:"R"},
             nsIDOMKeyEvent.DOM_VK_R, "R", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_R, ctrl:1, chars:"\u0012", unmodifiedChars:"r"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_R,
+             modifiers:{ctrlKey:1}, chars:"\u0012", unmodifiedChars:"r"},
             nsIDOMKeyEvent.DOM_VK_R, "r", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_R, alt:1, chars:"\u00AE", unmodifiedChars:"r"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_R,
+             modifiers:{altKey:1}, chars:"\u00AE", unmodifiedChars:"r"},
             nsIDOMKeyEvent.DOM_VK_R, "\u00AE", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // XXX This test makes some tabs and dialogs.
-    // testKey({layout:"US", keyCode:MAC_VK_ANSI_R, command:1, chars:"r", unmodifiedChars:"r"},
+    // testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_R,
+    //          modifiers:{metaKey:1}, chars:"r", unmodifiedChars:"r"},
     //         nsIDOMKeyEvent.DOM_VK_R, "r", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_S, chars:"s", unmodifiedChars:"s"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_S,
+             modifiers:{}, chars:"s", unmodifiedChars:"s"},
             nsIDOMKeyEvent.DOM_VK_S, "s", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_S, shift:1, chars:"S", unmodifiedChars:"S"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_S,
+             modifiers:{shiftKey:1}, chars:"S", unmodifiedChars:"S"},
             nsIDOMKeyEvent.DOM_VK_S, "S", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_S, ctrl:1, chars:"\u0013", unmodifiedChars:"s"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_S,
+             modifiers:{ctrlKey:1}, chars:"\u0013", unmodifiedChars:"s"},
             nsIDOMKeyEvent.DOM_VK_S, "s", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_S, alt:1, chars:"\u00DF", unmodifiedChars:"s"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_S,
+             modifiers:{altKey:1}, chars:"\u00DF", unmodifiedChars:"s"},
             nsIDOMKeyEvent.DOM_VK_S, "\u00DF", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_S, command:1, chars:"s", unmodifiedChars:"s"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_S,
+             modifiers:{metaKey:1}, chars:"s", unmodifiedChars:"s"},
             nsIDOMKeyEvent.DOM_VK_S, "s", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_T, chars:"t", unmodifiedChars:"t"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_T,
+             modifiers:{}, chars:"t", unmodifiedChars:"t"},
             nsIDOMKeyEvent.DOM_VK_T, "t", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_T, shift:1, chars:"T", unmodifiedChars:"T"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_T,
+             modifiers:{shiftKey:1}, chars:"T", unmodifiedChars:"T"},
             nsIDOMKeyEvent.DOM_VK_T, "T", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_T, ctrl:1, chars:"\u0014", unmodifiedChars:"t"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_T,
+             modifiers:{ctrlKey:1}, chars:"\u0014", unmodifiedChars:"t"},
             nsIDOMKeyEvent.DOM_VK_T, "t", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_T, alt:1, chars:"\u2020", unmodifiedChars:"t"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_T,
+             modifiers:{altKey:1}, chars:"\u2020", unmodifiedChars:"t"},
             nsIDOMKeyEvent.DOM_VK_T, "\u2020", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_T, command:1, chars:"t", unmodifiedChars:"t"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_T,
+             modifiers:{metaKey:1}, chars:"t", unmodifiedChars:"t"},
             nsIDOMKeyEvent.DOM_VK_T, "t", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_U, chars:"u", unmodifiedChars:"u"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_U,
+             modifiers:{}, chars:"u", unmodifiedChars:"u"},
             nsIDOMKeyEvent.DOM_VK_U, "u", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_U, shift:1, chars:"U", unmodifiedChars:"U"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_U,
+             modifiers:{shiftKey:1}, chars:"U", unmodifiedChars:"U"},
             nsIDOMKeyEvent.DOM_VK_U, "U", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_U, ctrl:1, chars:"\u0015", unmodifiedChars:"u"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_U,
+             modifiers:{ctrlKey:1}, chars:"\u0015", unmodifiedChars:"u"},
             nsIDOMKeyEvent.DOM_VK_U, "u", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_U, alt:1, chars:"", unmodifiedChars:"u"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_U,
+             modifiers:{altKey:1}, chars:"", unmodifiedChars:"u"},
             nsIDOMKeyEvent.DOM_VK_U, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // dead key
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_U, command:1, chars:"u", unmodifiedChars:"u"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_U,
+             modifiers:{metaKey:1}, chars:"u", unmodifiedChars:"u"},
             nsIDOMKeyEvent.DOM_VK_U, "u", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_V, chars:"v", unmodifiedChars:"v"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_V,
+             modifiers:{}, chars:"v", unmodifiedChars:"v"},
             nsIDOMKeyEvent.DOM_VK_V, "v", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_V, shift:1, chars:"V", unmodifiedChars:"V"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_V,
+             modifiers:{shiftKey:1}, chars:"V", unmodifiedChars:"V"},
             nsIDOMKeyEvent.DOM_VK_V, "V", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_V, ctrl:1, chars:"\u0016", unmodifiedChars:"v"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_V,
+             modifiers:{ctrlKey:1}, chars:"\u0016", unmodifiedChars:"v"},
             nsIDOMKeyEvent.DOM_VK_V, "v", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_V, alt:1, chars:"\u221A", unmodifiedChars:"v"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_V,
+             modifiers:{altKey:1}, chars:"\u221A", unmodifiedChars:"v"},
             nsIDOMKeyEvent.DOM_VK_V, "\u221A", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_V, command:1, chars:"v", unmodifiedChars:"v"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_V,
+             modifiers:{metaKey:1}, chars:"v", unmodifiedChars:"v"},
             nsIDOMKeyEvent.DOM_VK_V, "v", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_W, chars:"w", unmodifiedChars:"w"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_W,
+             modifiers:{}, chars:"w", unmodifiedChars:"w"},
             nsIDOMKeyEvent.DOM_VK_W, "w", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_W, shift:1, chars:"W", unmodifiedChars:"W"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_W,
+             modifiers:{shiftKey:1}, chars:"W", unmodifiedChars:"W"},
             nsIDOMKeyEvent.DOM_VK_W, "W", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_W, ctrl:1, chars:"\u0017", unmodifiedChars:"w"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_W,
+             modifiers:{ctrlKey:1}, chars:"\u0017", unmodifiedChars:"w"},
             nsIDOMKeyEvent.DOM_VK_W, "w", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_W, alt:1, chars:"\u2211", unmodifiedChars:"w"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_W,
+             modifiers:{altKey:1}, chars:"\u2211", unmodifiedChars:"w"},
             nsIDOMKeyEvent.DOM_VK_W, "\u2211", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_W, command:1, chars:"w", unmodifiedChars:"w"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_W,
+             modifiers:{metaKey:1}, chars:"w", unmodifiedChars:"w"},
             nsIDOMKeyEvent.DOM_VK_W, "w", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_X, chars:"x", unmodifiedChars:"x"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_X,
+             modifiers:{}, chars:"x", unmodifiedChars:"x"},
             nsIDOMKeyEvent.DOM_VK_X, "x", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_X, shift:1, chars:"X", unmodifiedChars:"X"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_X,
+             modifiers:{shiftKey:1}, chars:"X", unmodifiedChars:"X"},
             nsIDOMKeyEvent.DOM_VK_X, "X", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_X, ctrl:1, chars:"\u0018", unmodifiedChars:"x"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_X,
+             modifiers:{ctrlKey:1}, chars:"\u0018", unmodifiedChars:"x"},
             nsIDOMKeyEvent.DOM_VK_X, "x", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_X, alt:1, chars:"\u2248", unmodifiedChars:"x"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_X,
+             modifiers:{altKey:1}, chars:"\u2248", unmodifiedChars:"x"},
             nsIDOMKeyEvent.DOM_VK_X, "\u2248", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_X, command:1, chars:"x", unmodifiedChars:"x"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_X,
+             modifiers:{metaKey:1}, chars:"x", unmodifiedChars:"x"},
             nsIDOMKeyEvent.DOM_VK_X, "x", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Y, chars:"y", unmodifiedChars:"y"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Y,
+             modifiers:{}, chars:"y", unmodifiedChars:"y"},
             nsIDOMKeyEvent.DOM_VK_Y, "y", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Y, shift:1, chars:"Y", unmodifiedChars:"Y"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Y,
+             modifiers:{shiftKey:1}, chars:"Y", unmodifiedChars:"Y"},
             nsIDOMKeyEvent.DOM_VK_Y, "Y", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Y, ctrl:1, chars:"\u0019", unmodifiedChars:"y"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Y,
+             modifiers:{ctrlKey:1}, chars:"\u0019", unmodifiedChars:"y"},
             nsIDOMKeyEvent.DOM_VK_Y, "y", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Y, alt:1, chars:"\u00A5", unmodifiedChars:"y"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Y,
+             modifiers:{altKey:1}, chars:"\u00A5", unmodifiedChars:"y"},
             nsIDOMKeyEvent.DOM_VK_Y, "\u00A5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Y, command:1, chars:"y", unmodifiedChars:"y"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Y,
+             modifiers:{metaKey:1}, chars:"y", unmodifiedChars:"y"},
             nsIDOMKeyEvent.DOM_VK_Y, "y", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Z, chars:"z", unmodifiedChars:"z"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Z,
+             modifiers:{}, chars:"z", unmodifiedChars:"z"},
             nsIDOMKeyEvent.DOM_VK_Z, "z", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Z, shift:1, chars:"Z", unmodifiedChars:"Z"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Z,
+             modifiers:{shiftKey:1}, chars:"Z", unmodifiedChars:"Z"},
             nsIDOMKeyEvent.DOM_VK_Z, "Z", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Z, ctrl:1, chars:"\u001A", unmodifiedChars:"z"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Z,
+             modifiers:{ctrlKey:1}, chars:"\u001A", unmodifiedChars:"z"},
             nsIDOMKeyEvent.DOM_VK_Z, "z", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Z, alt:1, chars:"\u03A9", unmodifiedChars:"z"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Z,
+             modifiers:{altKey:1}, chars:"\u03A9", unmodifiedChars:"z"},
             nsIDOMKeyEvent.DOM_VK_Z, "\u03A9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Z, command:1, chars:"z", unmodifiedChars:"z"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Z,
+             modifiers:{metaKey:1}, chars:"z", unmodifiedChars:"z"},
             nsIDOMKeyEvent.DOM_VK_Z, "z", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // numeric
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_1, chars:"1", unmodifiedChars:"1"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_1,
+             modifiers:{}, chars:"1", unmodifiedChars:"1"},
             nsIDOMKeyEvent.DOM_VK_1, "1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_1, shift:1, chars:"!", unmodifiedChars:"!"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_1,
+             modifiers:{shiftKey:1}, chars:"!", unmodifiedChars:"!"},
             nsIDOMKeyEvent.DOM_VK_1, "!", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_1, ctrl:1, chars:"1", unmodifiedChars:"1"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_1,
+             modifiers:{ctrlKey:1}, chars:"1", unmodifiedChars:"1"},
             nsIDOMKeyEvent.DOM_VK_1, "1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_1, alt:1, chars:"\u00A1", unmodifiedChars:"1"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_1,
+             modifiers:{altKey:1}, chars:"\u00A1", unmodifiedChars:"1"},
             nsIDOMKeyEvent.DOM_VK_1, "\u00A1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_1, command:1, chars:"1", unmodifiedChars:"1"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_1,
+             modifiers:{metaKey:1}, chars:"1", unmodifiedChars:"1"},
             nsIDOMKeyEvent.DOM_VK_1, "1", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_2, chars:"2", unmodifiedChars:"2"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_2,
+             modifiers:{}, chars:"2", unmodifiedChars:"2"},
             nsIDOMKeyEvent.DOM_VK_2, "2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_2, shift:1, chars:"@", unmodifiedChars:"@"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_2,
+             modifiers:{shiftKey:1}, chars:"@", unmodifiedChars:"@"},
             nsIDOMKeyEvent.DOM_VK_2, "@", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_2, ctrl:1, chars:"2", unmodifiedChars:"2"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_2,
+             modifiers:{ctrlKey:1}, chars:"2", unmodifiedChars:"2"},
             nsIDOMKeyEvent.DOM_VK_2, "2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_2, alt:1, chars:"\u00A1", unmodifiedChars:"2"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_2,
+             modifiers:{altKey:1}, chars:"\u00A1", unmodifiedChars:"2"},
             nsIDOMKeyEvent.DOM_VK_2, "\u00A1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_2, command:1, chars:"2", unmodifiedChars:"2"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_2,
+             modifiers:{metaKey:1}, chars:"2", unmodifiedChars:"2"},
             nsIDOMKeyEvent.DOM_VK_2, "2", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_3, chars:"3", unmodifiedChars:"3"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_3,
+             modifiers:{}, chars:"3", unmodifiedChars:"3"},
             nsIDOMKeyEvent.DOM_VK_3, "3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_3, shift:1, chars:"#", unmodifiedChars:"#"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_3,
+             modifiers:{shiftKey:1}, chars:"#", unmodifiedChars:"#"},
             nsIDOMKeyEvent.DOM_VK_3, "#", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_3, ctrl:1, chars:"3", unmodifiedChars:"3"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_3,
+             modifiers:{ctrlKey:1}, chars:"3", unmodifiedChars:"3"},
             nsIDOMKeyEvent.DOM_VK_3, "3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_3, alt:1, chars:"\u00A3", unmodifiedChars:"3"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_3,
+             modifiers:{altKey:1}, chars:"\u00A3", unmodifiedChars:"3"},
             nsIDOMKeyEvent.DOM_VK_3, "\u00A3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_3, command:1, chars:"3", unmodifiedChars:"3"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_3,
+             modifiers:{metaKey:1}, chars:"3", unmodifiedChars:"3"},
             nsIDOMKeyEvent.DOM_VK_3, "3", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_4, chars:"4", unmodifiedChars:"4"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_4,
+             modifiers:{}, chars:"4", unmodifiedChars:"4"},
             nsIDOMKeyEvent.DOM_VK_4, "4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_4, shift:1, chars:"$", unmodifiedChars:"$"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_4,
+             modifiers:{shiftKey:1}, chars:"$", unmodifiedChars:"$"},
             nsIDOMKeyEvent.DOM_VK_4, "$", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_4, ctrl:1, chars:"4", unmodifiedChars:"4"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_4,
+             modifiers:{ctrlKey:1}, chars:"4", unmodifiedChars:"4"},
             nsIDOMKeyEvent.DOM_VK_4, "4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_4, alt:1, chars:"\u00A2", unmodifiedChars:"4"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_4,
+             modifiers:{altKey:1}, chars:"\u00A2", unmodifiedChars:"4"},
             nsIDOMKeyEvent.DOM_VK_4, "\u00A2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_4, command:1, chars:"4", unmodifiedChars:"4"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_4,
+             modifiers:{metaKey:1}, chars:"4", unmodifiedChars:"4"},
             nsIDOMKeyEvent.DOM_VK_4, "4", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_5, chars:"5", unmodifiedChars:"5"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_5,
+             modifiers:{}, chars:"5", unmodifiedChars:"5"},
             nsIDOMKeyEvent.DOM_VK_5, "5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_5, shift:1, chars:"%", unmodifiedChars:"%"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_5,
+             modifiers:{shiftKey:1}, chars:"%", unmodifiedChars:"%"},
             nsIDOMKeyEvent.DOM_VK_5, "%", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_5, ctrl:1, chars:"5", unmodifiedChars:"5"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_5,
+             modifiers:{ctrlKey:1}, chars:"5", unmodifiedChars:"5"},
             nsIDOMKeyEvent.DOM_VK_5, "5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_5, alt:1, chars:"\u221E", unmodifiedChars:"5"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_5,
+             modifiers:{altKey:1}, chars:"\u221E", unmodifiedChars:"5"},
             nsIDOMKeyEvent.DOM_VK_5, "\u221E", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_5, command:1, chars:"5", unmodifiedChars:"5"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_5,
+             modifiers:{metaKey:1}, chars:"5", unmodifiedChars:"5"},
             nsIDOMKeyEvent.DOM_VK_5, "5", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_6, chars:"6", unmodifiedChars:"6"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_6,
+             modifiers:{}, chars:"6", unmodifiedChars:"6"},
             nsIDOMKeyEvent.DOM_VK_6, "6", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_6, shift:1, chars:"^", unmodifiedChars:"^"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_6,
+             modifiers:{shiftKey:1}, chars:"^", unmodifiedChars:"^"},
             nsIDOMKeyEvent.DOM_VK_6, "^", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_6, ctrl:1, chars:"6", unmodifiedChars:"6"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_6,
+             modifiers:{ctrlKey:1}, chars:"6", unmodifiedChars:"6"},
             nsIDOMKeyEvent.DOM_VK_6, "6", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_6, alt:1, chars:"\u00A7", unmodifiedChars:"6"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_6,
+             modifiers:{altKey:1}, chars:"\u00A7", unmodifiedChars:"6"},
             nsIDOMKeyEvent.DOM_VK_6, "\u00A7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_6, command:1, chars:"6", unmodifiedChars:"6"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_6,
+             modifiers:{metaKey:1}, chars:"6", unmodifiedChars:"6"},
             nsIDOMKeyEvent.DOM_VK_6, "6", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_7, chars:"7", unmodifiedChars:"7"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_7,
+             modifiers:{}, chars:"7", unmodifiedChars:"7"},
             nsIDOMKeyEvent.DOM_VK_7, "7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_7, shift:1, chars:"\u0026;", unmodifiedChars:"\u0026;"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_7,
+             modifiers:{shiftKey:1}, chars:"\u0026;", unmodifiedChars:"\u0026;"},
             nsIDOMKeyEvent.DOM_VK_7, "\u0026", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_7, ctrl:1, chars:"7", unmodifiedChars:"7"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_7,
+             modifiers:{ctrlKey:1}, chars:"7", unmodifiedChars:"7"},
             nsIDOMKeyEvent.DOM_VK_7, "7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_7, alt:1, chars:"\u00B6", unmodifiedChars:"7"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_7,
+             modifiers:{altKey:1}, chars:"\u00B6", unmodifiedChars:"7"},
             nsIDOMKeyEvent.DOM_VK_7, "\u00B6", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_7, command:1, chars:"7", unmodifiedChars:"7"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_7,
+             modifiers:{metaKey:1}, chars:"7", unmodifiedChars:"7"},
             nsIDOMKeyEvent.DOM_VK_7, "7", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_8, chars:"8", unmodifiedChars:"8"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_8,
+             modifiers:{}, chars:"8", unmodifiedChars:"8"},
             nsIDOMKeyEvent.DOM_VK_8, "8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_8, shift:1, chars:"*", unmodifiedChars:"*"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_8,
+             modifiers:{shiftKey:1}, chars:"*", unmodifiedChars:"*"},
             nsIDOMKeyEvent.DOM_VK_8, "*", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_8, ctrl:1, chars:"8", unmodifiedChars:"8"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_8,
+             modifiers:{ctrlKey:1}, chars:"8", unmodifiedChars:"8"},
             nsIDOMKeyEvent.DOM_VK_8, "8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_8, alt:1, chars:"\u2022", unmodifiedChars:"8"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_8,
+             modifiers:{altKey:1}, chars:"\u2022", unmodifiedChars:"8"},
             nsIDOMKeyEvent.DOM_VK_8, "\u2022", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_8, command:1, chars:"8", unmodifiedChars:"8"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_8,
+             modifiers:{metaKey:1}, chars:"8", unmodifiedChars:"8"},
             nsIDOMKeyEvent.DOM_VK_8, "8", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_9, chars:"9", unmodifiedChars:"9"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_9,
+             modifiers:{}, chars:"9", unmodifiedChars:"9"},
             nsIDOMKeyEvent.DOM_VK_9, "9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_9, shift:1, chars:"(", unmodifiedChars:"("},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_9,
+             modifiers:{shiftKey:1}, chars:"(", unmodifiedChars:"("},
             nsIDOMKeyEvent.DOM_VK_9, "(", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_9, ctrl:1, chars:"9", unmodifiedChars:"9"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_9,
+             modifiers:{ctrlKey:1}, chars:"9", unmodifiedChars:"9"},
             nsIDOMKeyEvent.DOM_VK_9, "9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_9, alt:1, chars:"\u00AA", unmodifiedChars:"9"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_9,
+             modifiers:{altKey:1}, chars:"\u00AA", unmodifiedChars:"9"},
             nsIDOMKeyEvent.DOM_VK_9, "\u00AA", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_9, command:1, chars:"9", unmodifiedChars:"9"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_9,
+             modifiers:{metaKey:1}, chars:"9", unmodifiedChars:"9"},
             nsIDOMKeyEvent.DOM_VK_9, "9", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_0, chars:"0", unmodifiedChars:"0"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_0,
+             modifiers:{}, chars:"0", unmodifiedChars:"0"},
             nsIDOMKeyEvent.DOM_VK_0, "0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_0, shift:1, chars:")", unmodifiedChars:")"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_0,
+             modifiers:{shiftKey:1}, chars:")", unmodifiedChars:")"},
             nsIDOMKeyEvent.DOM_VK_0, ")", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_0, ctrl:1, chars:"0", unmodifiedChars:"0"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_0,
+             modifiers:{ctrlKey:1}, chars:"0", unmodifiedChars:"0"},
             nsIDOMKeyEvent.DOM_VK_0, "0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_0, alt:1, chars:"\u00BA", unmodifiedChars:"0"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_0,
+             modifiers:{altKey:1}, chars:"\u00BA", unmodifiedChars:"0"},
             nsIDOMKeyEvent.DOM_VK_0, "\u00BA", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_0, command:1, chars:"0", unmodifiedChars:"0"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_0,
+             modifiers:{metaKey:1}, chars:"0", unmodifiedChars:"0"},
             nsIDOMKeyEvent.DOM_VK_0, "0", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // other chracters
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Grave, chars:"`", unmodifiedChars:"`"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Grave,
+             modifiers:{}, chars:"`", unmodifiedChars:"`"},
             nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "`", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Grave, shift:1, chars:"~", unmodifiedChars:"~"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Grave,
+             modifiers:{shiftKey:1}, chars:"~", unmodifiedChars:"~"},
             nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "~", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Grave, ctrl:1, chars:"`", unmodifiedChars:"`"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Grave,
+             modifiers:{ctrlKey:1}, chars:"`", unmodifiedChars:"`"},
             nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "`", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Grave, alt:1, chars:"", unmodifiedChars:"`"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Grave,
+             modifiers:{altKey:1}, chars:"", unmodifiedChars:"`"},
             nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // dead key
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Grave, command:1, chars:"`", unmodifiedChars:"`"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Grave,
+             modifiers:{metaKey:1}, chars:"`", unmodifiedChars:"`"},
             nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "`", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Minus, chars:"-", unmodifiedChars:"-"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Minus,
+             modifiers:{}, chars:"-", unmodifiedChars:"-"},
             nsIDOMKeyEvent.DOM_VK_HYPHEN_MINUS, "-", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Minus, shift:1, chars:"_", unmodifiedChars:"_"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Minus,
+             modifiers:{shiftKey:1}, chars:"_", unmodifiedChars:"_"},
             nsIDOMKeyEvent.DOM_VK_HYPHEN_MINUS, "_", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // TODO:
-    // testKey({layout:"US", keyCode:MAC_VK_ANSI_Minus, ctrl:1, chars:"\u001F", unmodifiedChars:"-"},
+    // testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Minus,
+    //          modifiers:{ctrlKey:1}, chars:"\u001F", unmodifiedChars:"-"},
     //         nsIDOMKeyEvent.DOM_VK_HYPHEN_MINUS, "-", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Minus, alt:1, chars:"\u2013", unmodifiedChars:"-"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Minus,
+             modifiers:{altKey:1}, chars:"\u2013", unmodifiedChars:"-"},
             nsIDOMKeyEvent.DOM_VK_HYPHEN_MINUS, "\u2013", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Minus, command:1, chars:"-", unmodifiedChars:"-"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Minus,
+             modifiers:{metaKey:1}, chars:"-", unmodifiedChars:"-"},
             nsIDOMKeyEvent.DOM_VK_HYPHEN_MINUS, "-", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Equal, chars:"=", unmodifiedChars:"="},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Equal,
+             modifiers:{}, chars:"=", unmodifiedChars:"="},
             nsIDOMKeyEvent.DOM_VK_EQUALS, "=", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Equal, shift:1, chars:"+", unmodifiedChars:"+"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Equal,
+             modifiers:{shiftKey:1}, chars:"+", unmodifiedChars:"+"},
             nsIDOMKeyEvent.DOM_VK_EQUALS, "+", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Equal, ctrl:1, chars:"=", unmodifiedChars:"="},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Equal,
+             modifiers:{ctrlKey:1}, chars:"=", unmodifiedChars:"="},
             nsIDOMKeyEvent.DOM_VK_EQUALS, "=", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Equal, alt:1, chars:"\u2260", unmodifiedChars:"="},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Equal,
+             modifiers:{altKey:1}, chars:"\u2260", unmodifiedChars:"="},
             nsIDOMKeyEvent.DOM_VK_EQUALS, "\u2260", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Equal, command:1, chars:"=", unmodifiedChars:"="},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Equal,
+             modifiers:{metaKey:1}, chars:"=", unmodifiedChars:"="},
             nsIDOMKeyEvent.DOM_VK_EQUALS, "=", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_LeftBracket, chars:"[", unmodifiedChars:"["},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_LeftBracket,
+             modifiers:{}, chars:"[", unmodifiedChars:"["},
             nsIDOMKeyEvent.DOM_VK_OPEN_BRACKET, "[", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_LeftBracket, shift:1, chars:"{", unmodifiedChars:"{"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_LeftBracket,
+             modifiers:{shiftKey:1}, chars:"{", unmodifiedChars:"{"},
             nsIDOMKeyEvent.DOM_VK_OPEN_BRACKET, "{", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // TODO:
-    // testKey({layout:"US", keyCode:MAC_VK_ANSI_LeftBracket, ctrl:1, chars:"\u001B", unmodifiedChars:"["},
+    // testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_LeftBracket,
+    //          modifiers:{ctrlKey:1}, chars:"\u001B", unmodifiedChars:"["},
     //         nsIDOMKeyEvent.DOM_VK_OPEN_BRACKET, "[", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_LeftBracket, alt:1, chars:"\u201C", unmodifiedChars:"["},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_LeftBracket,
+             modifiers:{altKey:1}, chars:"\u201C", unmodifiedChars:"["},
             nsIDOMKeyEvent.DOM_VK_OPEN_BRACKET, "\u201C", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_LeftBracket, command:1, chars:"[", unmodifiedChars:"["},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_LeftBracket,
+             modifiers:{metaKey:1}, chars:"[", unmodifiedChars:"["},
             nsIDOMKeyEvent.DOM_VK_OPEN_BRACKET, "[", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_RightBracket, chars:"]", unmodifiedChars:"]"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_RightBracket,
+             modifiers:{}, chars:"]", unmodifiedChars:"]"},
             nsIDOMKeyEvent.DOM_VK_CLOSE_BRACKET, "]", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_RightBracket, shift:1, chars:"}", unmodifiedChars:"}"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_RightBracket,
+             modifiers:{shiftKey:1}, chars:"}", unmodifiedChars:"}"},
             nsIDOMKeyEvent.DOM_VK_CLOSE_BRACKET, "}", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // TODO:
-    // testKey({layout:"US", keyCode:MAC_VK_ANSI_RightBracket, ctrl:1, chars:"\u001D", unmodifiedChars:"]"},
+    // testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_RightBracket,
+    //          modifiers:{ctrlKey:1}, chars:"\u001D", unmodifiedChars:"]"},
     //         nsIDOMKeyEvent.DOM_VK_CLOSE_BRACKET, "]", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_RightBracket, alt:1, chars:"\u2018", unmodifiedChars:"]"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_RightBracket,
+             modifiers:{altKey:1}, chars:"\u2018", unmodifiedChars:"]"},
             nsIDOMKeyEvent.DOM_VK_CLOSE_BRACKET, "\u2018", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_RightBracket, command:1, chars:"]", unmodifiedChars:"]"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_RightBracket,
+             modifiers:{metaKey:1}, chars:"]", unmodifiedChars:"]"},
             nsIDOMKeyEvent.DOM_VK_CLOSE_BRACKET, "]", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Backslash, chars:"\\", unmodifiedChars:"\\"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Backslash,
+             modifiers:{}, chars:"\\", unmodifiedChars:"\\"},
             nsIDOMKeyEvent.DOM_VK_BACK_SLASH, "\\", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Backslash, shift:1, chars:"|", unmodifiedChars:"|"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Backslash,
+             modifiers:{shiftKey:1}, chars:"|", unmodifiedChars:"|"},
             nsIDOMKeyEvent.DOM_VK_BACK_SLASH, "|", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // TODO:
-    // testKey({layout:"US", keyCode:MAC_VK_ANSI_Backslash, ctrl:1, chars:"\u001C", unmodifiedChars:"\\"},
+    // testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Backslash,
+    //          modifiers:{ctrlKey:1}, chars:"\u001C", unmodifiedChars:"\\"},
     //         nsIDOMKeyEvent.DOM_VK_BACK_SLASH, "\\", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Backslash, alt:1, chars:"\u00AB", unmodifiedChars:"\\"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Backslash,
+             modifiers:{altKey:1}, chars:"\u00AB", unmodifiedChars:"\\"},
             nsIDOMKeyEvent.DOM_VK_BACK_SLASH, "\u00AB", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Backslash, command:1, chars:"\\", unmodifiedChars:"\\"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Backslash,
+             modifiers:{metaKey:1}, chars:"\\", unmodifiedChars:"\\"},
             nsIDOMKeyEvent.DOM_VK_BACK_SLASH, "\\", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Semicolon, chars:";", unmodifiedChars:";"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Semicolon,
+             modifiers:{}, chars:";", unmodifiedChars:";"},
             nsIDOMKeyEvent.DOM_VK_SEMICOLON, ";", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Semicolon, shift:1, chars:":", unmodifiedChars:":"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Semicolon,
+             modifiers:{shiftKey:1}, chars:":", unmodifiedChars:":"},
             nsIDOMKeyEvent.DOM_VK_SEMICOLON, ":", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Semicolon, ctrl:1, chars:";", unmodifiedChars:";"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Semicolon,
+             modifiers:{ctrlKey:1}, chars:";", unmodifiedChars:";"},
             nsIDOMKeyEvent.DOM_VK_SEMICOLON, ";", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Semicolon, alt:1, chars:"\u2026", unmodifiedChars:";"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Semicolon,
+             modifiers:{altKey:1}, chars:"\u2026", unmodifiedChars:";"},
             nsIDOMKeyEvent.DOM_VK_SEMICOLON, "\u2026", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Semicolon, command:1, chars:";", unmodifiedChars:";"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Semicolon,
+             modifiers:{metaKey:1}, chars:";", unmodifiedChars:";"},
             nsIDOMKeyEvent.DOM_VK_SEMICOLON, ";", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Quote, chars:"'", unmodifiedChars:"'"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Quote,
+             modifiers:{}, chars:"'", unmodifiedChars:"'"},
             nsIDOMKeyEvent.DOM_VK_QUOTE, "'", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Quote, shift:1, chars:"\"", unmodifiedChars:"\""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Quote,
+             modifiers:{shiftKey:1}, chars:"\"", unmodifiedChars:"\""},
             nsIDOMKeyEvent.DOM_VK_QUOTE, "\"", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Quote, ctrl:1, chars:"'", unmodifiedChars:"'"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Quote,
+             modifiers:{ctrlKey:1}, chars:"'", unmodifiedChars:"'"},
             nsIDOMKeyEvent.DOM_VK_QUOTE, "'", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Quote, alt:1, chars:"\u00E6", unmodifiedChars:"'"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Quote,
+             modifiers:{altKey:1}, chars:"\u00E6", unmodifiedChars:"'"},
             nsIDOMKeyEvent.DOM_VK_QUOTE, "\u00E6", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Quote, command:1, chars:"'", unmodifiedChars:"'"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Quote,
+             modifiers:{metaKey:1}, chars:"'", unmodifiedChars:"'"},
             nsIDOMKeyEvent.DOM_VK_QUOTE, "'", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Comma, chars:",", unmodifiedChars:","},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Comma,
+             modifiers:{}, chars:",", unmodifiedChars:","},
             nsIDOMKeyEvent.DOM_VK_COMMA, ",", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Comma, shift:1, chars:"\u003C", unmodifiedChars:"\u003C"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Comma,
+             modifiers:{shiftKey:1}, chars:"\u003C", unmodifiedChars:"\u003C"},
             nsIDOMKeyEvent.DOM_VK_COMMA, "\u003C", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Comma, ctrl:1, chars:",", unmodifiedChars:","},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Comma,
+             modifiers:{ctrlKey:1}, chars:",", unmodifiedChars:","},
             nsIDOMKeyEvent.DOM_VK_COMMA, ",", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Comma, alt:1, chars:"\u2264", unmodifiedChars:","},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Comma,
+             modifiers:{altKey:1}, chars:"\u2264", unmodifiedChars:","},
             nsIDOMKeyEvent.DOM_VK_COMMA, "\u2264", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Comma, command:1, chars:",", unmodifiedChars:","},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Comma,
+             modifiers:{metaKey:1}, chars:",", unmodifiedChars:","},
             nsIDOMKeyEvent.DOM_VK_COMMA, ",", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Period, chars:".", unmodifiedChars:"."},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Period,
+             modifiers:{}, chars:".", unmodifiedChars:"."},
             nsIDOMKeyEvent.DOM_VK_PERIOD, ".", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Period, shift:1, chars:"\u003E", unmodifiedChars:"\u003E"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Period,
+             modifiers:{shiftKey:1}, chars:"\u003E", unmodifiedChars:"\u003E"},
             nsIDOMKeyEvent.DOM_VK_PERIOD, "\u003E", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Period, ctrl:1, chars:".", unmodifiedChars:"."},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Period,
+             modifiers:{ctrlKey:1}, chars:".", unmodifiedChars:"."},
             nsIDOMKeyEvent.DOM_VK_PERIOD, ".", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Period, alt:1, chars:"\u2265", unmodifiedChars:"."},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Period,
+             modifiers:{altKey:1}, chars:"\u2265", unmodifiedChars:"."},
             nsIDOMKeyEvent.DOM_VK_PERIOD, "\u2265", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Period, command:1, chars:".", unmodifiedChars:"."},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Period,
+             modifiers:{metaKey:1}, chars:".", unmodifiedChars:"."},
             nsIDOMKeyEvent.DOM_VK_PERIOD, ".", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Slash, chars:"/", unmodifiedChars:"/"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Slash,
+             modifiers:{}, chars:"/", unmodifiedChars:"/"},
             nsIDOMKeyEvent.DOM_VK_SLASH, "/", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Slash, shift:1, chars:"?", unmodifiedChars:"?"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Slash,
+             modifiers:{shiftKey:1}, chars:"?", unmodifiedChars:"?"},
             nsIDOMKeyEvent.DOM_VK_SLASH, "?", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Slash, ctrl:1, chars:"/", unmodifiedChars:"/"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Slash,
+             modifiers:{ctrlKey:1}, chars:"/", unmodifiedChars:"/"},
             nsIDOMKeyEvent.DOM_VK_SLASH, "/", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Slash, alt:1, chars:"\u00F7", unmodifiedChars:"/"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Slash,
+             modifiers:{altKey:1}, chars:"\u00F7", unmodifiedChars:"/"},
             nsIDOMKeyEvent.DOM_VK_SLASH, "\u00F7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Slash, command:1, chars:"/", unmodifiedChars:"/"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Slash,
+             modifiers:{metaKey:1}, chars:"/", unmodifiedChars:"/"},
             nsIDOMKeyEvent.DOM_VK_SLASH, "/", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // numpad
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad1, numLock:1, chars:"1", unmodifiedChars:"1"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad1,
+             modifiers:{numericKeyPadKey:1}, chars:"1", unmodifiedChars:"1"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD1, "1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad1, numLock:1, shift:1, chars:"1", unmodifiedChars:"1"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad1,
+             modifiers:{numericKeyPadKey:1, shiftKey:1}, chars:"1", unmodifiedChars:"1"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD1, "1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad1, numLock:1, ctrl:1, chars:"1", unmodifiedChars:"1"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad1,
+             modifiers:{numericKeyPadKey:1, ctrlKey:1}, chars:"1", unmodifiedChars:"1"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD1, "1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad1, numLock:1, alt:1, chars:"1", unmodifiedChars:"1"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad1,
+             modifiers:{numericKeyPadKey:1, altKey:1}, chars:"1", unmodifiedChars:"1"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD1, "1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad1, numLock:1, command:1, chars:"1", unmodifiedChars:"1"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad1,
+             modifiers:{numericKeyPadKey:1, metaKey:1}, chars:"1", unmodifiedChars:"1"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD1, "1", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad2, numLock:1, chars:"2", unmodifiedChars:"2"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad2,
+             modifiers:{numericKeyPadKey:1}, chars:"2", unmodifiedChars:"2"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD2, "2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad2, numLock:1, shift:1, chars:"2", unmodifiedChars:"2"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad2,
+             modifiers:{numericKeyPadKey:1, shiftKey:1}, chars:"2", unmodifiedChars:"2"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD2, "2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad2, numLock:1, ctrl:1, chars:"2", unmodifiedChars:"2"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad2,
+             modifiers:{numericKeyPadKey:1, ctrlKey:1}, chars:"2", unmodifiedChars:"2"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD2, "2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad2, numLock:1, alt:1, chars:"2", unmodifiedChars:"2"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad2,
+             modifiers:{numericKeyPadKey:1, altKey:1}, chars:"2", unmodifiedChars:"2"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD2, "2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad2, numLock:1, command:1, chars:"2", unmodifiedChars:"2"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad2,
+             modifiers:{numericKeyPadKey:1, metaKey:1}, chars:"2", unmodifiedChars:"2"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD2, "2", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad3, numLock:1, chars:"3", unmodifiedChars:"3"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad3,
+             modifiers:{numericKeyPadKey:1}, chars:"3", unmodifiedChars:"3"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD3, "3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad3, numLock:1, shift:1, chars:"3", unmodifiedChars:"3"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad3,
+             modifiers:{numericKeyPadKey:1, shiftKey:1}, chars:"3", unmodifiedChars:"3"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD3, "3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad3, numLock:1, ctrl:1, chars:"3", unmodifiedChars:"3"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad3,
+             modifiers:{numericKeyPadKey:1, ctrlKey:1}, chars:"3", unmodifiedChars:"3"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD3, "3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad3, numLock:1, alt:1, chars:"3", unmodifiedChars:"3"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad3,
+             modifiers:{numericKeyPadKey:1, altKey:1}, chars:"3", unmodifiedChars:"3"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD3, "3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad3, numLock:1, command:1, chars:"3", unmodifiedChars:"3"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad3,
+             modifiers:{numericKeyPadKey:1, metaKey:1}, chars:"3", unmodifiedChars:"3"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD3, "3", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad4, numLock:1, chars:"4", unmodifiedChars:"4"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad4,
+             modifiers:{numericKeyPadKey:1}, chars:"4", unmodifiedChars:"4"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD4, "4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad4, numLock:1, shift:1, chars:"4", unmodifiedChars:"4"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad4,
+             modifiers:{numericKeyPadKey:1, shiftKey:1}, chars:"4", unmodifiedChars:"4"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD4, "4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad4, numLock:1, ctrl:1, chars:"4", unmodifiedChars:"4"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad4,
+             modifiers:{numericKeyPadKey:1, ctrlKey:1}, chars:"4", unmodifiedChars:"4"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD4, "4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad4, numLock:1, alt:1, chars:"4", unmodifiedChars:"4"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad4,
+             modifiers:{numericKeyPadKey:1, altKey:1}, chars:"4", unmodifiedChars:"4"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD4, "4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad4, numLock:1, command:1, chars:"4", unmodifiedChars:"4"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad4,
+             modifiers:{numericKeyPadKey:1, metaKey:1}, chars:"4", unmodifiedChars:"4"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD4, "4", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad5, numLock:1, chars:"5", unmodifiedChars:"5"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad5,
+             modifiers:{numericKeyPadKey:1}, chars:"5", unmodifiedChars:"5"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD5, "5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad5, numLock:1, shift:1, chars:"5", unmodifiedChars:"5"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad5,
+             modifiers:{numericKeyPadKey:1, shiftKey:1}, chars:"5", unmodifiedChars:"5"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD5, "5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad5, numLock:1, ctrl:1, chars:"5", unmodifiedChars:"5"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad5,
+             modifiers:{numericKeyPadKey:1, ctrlKey:1}, chars:"5", unmodifiedChars:"5"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD5, "5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad5, numLock:1, alt:1, chars:"5", unmodifiedChars:"5"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad5,
+             modifiers:{numericKeyPadKey:1, altKey:1}, chars:"5", unmodifiedChars:"5"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD5, "5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad5, numLock:1, command:1, chars:"5", unmodifiedChars:"5"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad5,
+             modifiers:{numericKeyPadKey:1, metaKey:1}, chars:"5", unmodifiedChars:"5"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD5, "5", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad6, numLock:1, chars:"6", unmodifiedChars:"6"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad6,
+             modifiers:{numericKeyPadKey:1}, chars:"6", unmodifiedChars:"6"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD6, "6", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad6, numLock:1, shift:1, chars:"6", unmodifiedChars:"6"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad6,
+             modifiers:{numericKeyPadKey:1, shiftKey:1}, chars:"6", unmodifiedChars:"6"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD6, "6", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad6, numLock:1, ctrl:1, chars:"6", unmodifiedChars:"6"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad6,
+             modifiers:{numericKeyPadKey:1, ctrlKey:1}, chars:"6", unmodifiedChars:"6"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD6, "6", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad6, numLock:1, alt:1, chars:"6", unmodifiedChars:"6"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad6,
+             modifiers:{numericKeyPadKey:1, altKey:1}, chars:"6", unmodifiedChars:"6"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD6, "6", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad6, numLock:1, command:1, chars:"6", unmodifiedChars:"6"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad6,
+             modifiers:{numericKeyPadKey:1, metaKey:1}, chars:"6", unmodifiedChars:"6"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD6, "6", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad7, numLock:1, chars:"7", unmodifiedChars:"7"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad7,
+             modifiers:{numericKeyPadKey:1}, chars:"7", unmodifiedChars:"7"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD7, "7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad7, numLock:1, shift:1, chars:"7", unmodifiedChars:"7"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad7,
+             modifiers:{numericKeyPadKey:1, shiftKey:1}, chars:"7", unmodifiedChars:"7"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD7, "7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad7, numLock:1, ctrl:1, chars:"7", unmodifiedChars:"7"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad7,
+             modifiers:{numericKeyPadKey:1, ctrlKey:1}, chars:"7", unmodifiedChars:"7"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD7, "7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad7, numLock:1, alt:1, chars:"7", unmodifiedChars:"7"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad7,
+             modifiers:{numericKeyPadKey:1, altKey:1}, chars:"7", unmodifiedChars:"7"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD7, "7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad7, numLock:1, command:1, chars:"7", unmodifiedChars:"7"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad7,
+             modifiers:{numericKeyPadKey:1, metaKey:1}, chars:"7", unmodifiedChars:"7"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD7, "7", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad8, numLock:1, chars:"8", unmodifiedChars:"8"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad8,
+             modifiers:{numericKeyPadKey:1}, chars:"8", unmodifiedChars:"8"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD8, "8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad8, numLock:1, shift:1, chars:"8", unmodifiedChars:"8"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad8,
+             modifiers:{numericKeyPadKey:1, shiftKey:1}, chars:"8", unmodifiedChars:"8"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD8, "8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad8, numLock:1, ctrl:1, chars:"8", unmodifiedChars:"8"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad8,
+             modifiers:{numericKeyPadKey:1, ctrlKey:1}, chars:"8", unmodifiedChars:"8"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD8, "8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad8, numLock:1, alt:1, chars:"8", unmodifiedChars:"8"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad8,
+             modifiers:{numericKeyPadKey:1, altKey:1}, chars:"8", unmodifiedChars:"8"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD8, "8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad8, numLock:1, command:1, chars:"8", unmodifiedChars:"8"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad8,
+             modifiers:{numericKeyPadKey:1, metaKey:1}, chars:"8", unmodifiedChars:"8"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD8, "8", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad9, numLock:1, chars:"9", unmodifiedChars:"9"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad9,
+             modifiers:{numericKeyPadKey:1}, chars:"9", unmodifiedChars:"9"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD9, "9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad9, numLock:1, shift:1, chars:"9", unmodifiedChars:"9"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad9,
+             modifiers:{numericKeyPadKey:1, shiftKey:1}, chars:"9", unmodifiedChars:"9"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD9, "9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad9, numLock:1, ctrl:1, chars:"9", unmodifiedChars:"9"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad9,
+             modifiers:{numericKeyPadKey:1, ctrlKey:1}, chars:"9", unmodifiedChars:"9"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD9, "9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad9, numLock:1, alt:1, chars:"9", unmodifiedChars:"9"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad9,
+             modifiers:{numericKeyPadKey:1, altKey:1}, chars:"9", unmodifiedChars:"9"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD9, "9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad9, numLock:1, command:1, chars:"9", unmodifiedChars:"9"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad9,
+             modifiers:{numericKeyPadKey:1, metaKey:1}, chars:"9", unmodifiedChars:"9"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD9, "9", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad0, numLock:1, chars:"0", unmodifiedChars:"0"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad0,
+             modifiers:{numericKeyPadKey:1}, chars:"0", unmodifiedChars:"0"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD0, "0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad0, numLock:1, shift:1, chars:"0", unmodifiedChars:"0"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad0,
+             modifiers:{numericKeyPadKey:1, shiftKey:1}, chars:"0", unmodifiedChars:"0"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD0, "0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad0, numLock:1, ctrl:1, chars:"0", unmodifiedChars:"0"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad0,
+             modifiers:{numericKeyPadKey:1, ctrlKey:1}, chars:"0", unmodifiedChars:"0"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD0, "0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad0, numLock:1, alt:1, chars:"0", unmodifiedChars:"0"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad0,
+             modifiers:{numericKeyPadKey:1, altKey:1}, chars:"0", unmodifiedChars:"0"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD0, "0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Keypad0, numLock:1, command:1, chars:"0", unmodifiedChars:"0"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Keypad0,
+             modifiers:{numericKeyPadKey:1, metaKey:1}, chars:"0", unmodifiedChars:"0"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD0, "0", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadEquals, numLock:1, chars:"=", unmodifiedChars:"="},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadEquals,
+             modifiers:{numericKeyPadKey:1}, chars:"=", unmodifiedChars:"="},
             nsIDOMKeyEvent.DOM_VK_EQUALS, "=", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadEquals, numLock:1, shift:1, chars:"=", unmodifiedChars:"="},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadEquals,
+             modifiers:{numericKeyPadKey:1, shiftKey:1}, chars:"=", unmodifiedChars:"="},
             nsIDOMKeyEvent.DOM_VK_EQUALS, "=", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadEquals, numLock:1, ctrl:1, chars:"=", unmodifiedChars:"="},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadEquals,
+             modifiers:{numericKeyPadKey:1, ctrlKey:1}, chars:"=", unmodifiedChars:"="},
             nsIDOMKeyEvent.DOM_VK_EQUALS, "=", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadEquals, numLock:1, alt:1, chars:"=", unmodifiedChars:"="},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadEquals,
+             modifiers:{numericKeyPadKey:1, altKey:1}, chars:"=", unmodifiedChars:"="},
             nsIDOMKeyEvent.DOM_VK_EQUALS, "=", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadEquals, numLock:1, command:1, chars:"=", unmodifiedChars:"="},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadEquals,
+             modifiers:{numericKeyPadKey:1, metaKey:1}, chars:"=", unmodifiedChars:"="},
             nsIDOMKeyEvent.DOM_VK_EQUALS, "=", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadDivide, numLock:1, chars:"/", unmodifiedChars:"/"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadDivide,
+             modifiers:{numericKeyPadKey:1}, chars:"/", unmodifiedChars:"/"},
             nsIDOMKeyEvent.DOM_VK_DIVIDE, "/", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadDivide, numLock:1, shift:1, chars:"/", unmodifiedChars:"/"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadDivide,
+             modifiers:{numericKeyPadKey:1, shiftKey:1}, chars:"/", unmodifiedChars:"/"},
             nsIDOMKeyEvent.DOM_VK_DIVIDE, "/", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadDivide, numLock:1, ctrl:1, chars:"/", unmodifiedChars:"/"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadDivide,
+             modifiers:{numericKeyPadKey:1, ctrlKey:1}, chars:"/", unmodifiedChars:"/"},
             nsIDOMKeyEvent.DOM_VK_DIVIDE, "/", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadDivide, numLock:1, alt:1, chars:"/", unmodifiedChars:"/"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadDivide,
+             modifiers:{numericKeyPadKey:1, altKey:1}, chars:"/", unmodifiedChars:"/"},
             nsIDOMKeyEvent.DOM_VK_DIVIDE, "/", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadDivide, numLock:1, command:1, chars:"/", unmodifiedChars:"/"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadDivide,
+             modifiers:{numericKeyPadKey:1, metaKey:1}, chars:"/", unmodifiedChars:"/"},
             nsIDOMKeyEvent.DOM_VK_DIVIDE, "/", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadMultiply, numLock:1, chars:"*", unmodifiedChars:"*"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadMultiply,
+             modifiers:{numericKeyPadKey:1}, chars:"*", unmodifiedChars:"*"},
             nsIDOMKeyEvent.DOM_VK_MULTIPLY, "*", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadMultiply, numLock:1, shift:1, chars:"*", unmodifiedChars:"*"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadMultiply,
+             modifiers:{numericKeyPadKey:1, shiftKey:1}, chars:"*", unmodifiedChars:"*"},
             nsIDOMKeyEvent.DOM_VK_MULTIPLY, "*", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadMultiply, numLock:1, ctrl:1, chars:"*", unmodifiedChars:"*"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadMultiply,
+             modifiers:{numericKeyPadKey:1, ctrlKey:1}, chars:"*", unmodifiedChars:"*"},
             nsIDOMKeyEvent.DOM_VK_MULTIPLY, "*", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadMultiply, numLock:1, alt:1, chars:"*", unmodifiedChars:"*"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadMultiply,
+             modifiers:{numericKeyPadKey:1, altKey:1}, chars:"*", unmodifiedChars:"*"},
             nsIDOMKeyEvent.DOM_VK_MULTIPLY, "*", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadMultiply, numLock:1, command:1, chars:"*", unmodifiedChars:"*"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadMultiply,
+             modifiers:{numericKeyPadKey:1, metaKey:1}, chars:"*", unmodifiedChars:"*"},
             nsIDOMKeyEvent.DOM_VK_MULTIPLY, "*", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadMinus, numLock:1, chars:"-", unmodifiedChars:"-"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadMinus,
+             modifiers:{numericKeyPadKey:1}, chars:"-", unmodifiedChars:"-"},
             nsIDOMKeyEvent.DOM_VK_SUBTRACT, "-", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadMinus, numLock:1, shift:1, chars:"-", unmodifiedChars:"-"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadMinus,
+             modifiers:{numericKeyPadKey:1, shiftKey:1}, chars:"-", unmodifiedChars:"-"},
             nsIDOMKeyEvent.DOM_VK_SUBTRACT, "-", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadMinus, numLock:1, ctrl:1, chars:"-", unmodifiedChars:"-"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadMinus,
+             modifiers:{numericKeyPadKey:1, ctrlKey:1}, chars:"-", unmodifiedChars:"-"},
             nsIDOMKeyEvent.DOM_VK_SUBTRACT, "-", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadMinus, numLock:1, alt:1, chars:"-", unmodifiedChars:"-"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadMinus,
+             modifiers:{numericKeyPadKey:1, altKey:1}, chars:"-", unmodifiedChars:"-"},
             nsIDOMKeyEvent.DOM_VK_SUBTRACT, "-", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadMinus, numLock:1, command:1, chars:"-", unmodifiedChars:"-"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadMinus,
+             modifiers:{numericKeyPadKey:1, metaKey:1}, chars:"-", unmodifiedChars:"-"},
             nsIDOMKeyEvent.DOM_VK_SUBTRACT, "-", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadPlus, numLock:1, chars:"+", unmodifiedChars:"+"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadPlus,
+             modifiers:{numericKeyPadKey:1}, chars:"+", unmodifiedChars:"+"},
             nsIDOMKeyEvent.DOM_VK_ADD, "+", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadPlus, numLock:1, shift:1, chars:"+", unmodifiedChars:"+"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadPlus,
+             modifiers:{numericKeyPadKey:1, shiftKey:1}, chars:"+", unmodifiedChars:"+"},
             nsIDOMKeyEvent.DOM_VK_ADD, "+", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadPlus, numLock:1, ctrl:1, chars:"+", unmodifiedChars:"+"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadPlus,
+             modifiers:{numericKeyPadKey:1, ctrlKey:1}, chars:"+", unmodifiedChars:"+"},
             nsIDOMKeyEvent.DOM_VK_ADD, "+", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadPlus, numLock:1, alt:1, chars:"+", unmodifiedChars:"+"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadPlus,
+             modifiers:{numericKeyPadKey:1, altKey:1}, chars:"+", unmodifiedChars:"+"},
             nsIDOMKeyEvent.DOM_VK_ADD, "+", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadPlus, numLock:1, command:1, chars:"+", unmodifiedChars:"+"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadPlus,
+             modifiers:{numericKeyPadKey:1, metaKey:1}, chars:"+", unmodifiedChars:"+"},
             nsIDOMKeyEvent.DOM_VK_ADD, "+", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadEnter, numLock:1, chars:"\u0003", unmodifiedChars:"\u0003"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadEnter,
+             modifiers:{numericKeyPadKey:1}, chars:"\u0003", unmodifiedChars:"\u0003"},
             nsIDOMKeyEvent.DOM_VK_RETURN, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadEnter, numLock:1, shift:1, chars:"\u0003", unmodifiedChars:"\u0003"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadEnter,
+             modifiers:{numericKeyPadKey:1, shiftKey:1}, chars:"\u0003", unmodifiedChars:"\u0003"},
             nsIDOMKeyEvent.DOM_VK_RETURN, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadEnter, numLock:1, ctrl:1, chars:"\u0003", unmodifiedChars:"\u0003"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadEnter,
+             modifiers:{numericKeyPadKey:1, ctrlKey:1}, chars:"\u0003", unmodifiedChars:"\u0003"},
             nsIDOMKeyEvent.DOM_VK_RETURN, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadEnter, numLock:1, alt:1, chars:"\u0003", unmodifiedChars:"\u0003"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadEnter,
+             modifiers:{numericKeyPadKey:1, altKey:1}, chars:"\u0003", unmodifiedChars:"\u0003"},
             nsIDOMKeyEvent.DOM_VK_RETURN, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_KeypadEnter, numLock:1, command:1, chars:"\u0003", unmodifiedChars:"\u0003"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_KeypadEnter,
+             modifiers:{numericKeyPadKey:1, metaKey:1}, chars:"\u0003", unmodifiedChars:"\u0003"},
             nsIDOMKeyEvent.DOM_VK_RETURN, "", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_JIS_KeypadComma, numLock:1, shift:1, chars:",", unmodifiedChars:","},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_JIS_KeypadComma,
+             modifiers:{numericKeyPadKey:1, shiftKey:1}, chars:",", unmodifiedChars:","},
             nsIDOMKeyEvent.DOM_VK_SEPARATOR, ",", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_JIS_KeypadComma, numLock:1, ctrl:1, chars:",", unmodifiedChars:","},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_JIS_KeypadComma,
+             modifiers:{numericKeyPadKey:1, ctrlKey:1}, chars:",", unmodifiedChars:","},
             nsIDOMKeyEvent.DOM_VK_SEPARATOR, ",", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_JIS_KeypadComma, numLock:1, alt:1, chars:",", unmodifiedChars:","},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_JIS_KeypadComma,
+             modifiers:{numericKeyPadKey:1, altKey:1}, chars:",", unmodifiedChars:","},
             nsIDOMKeyEvent.DOM_VK_SEPARATOR, ",", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:MAC_VK_JIS_KeypadComma, numLock:1, command:1, chars:",", unmodifiedChars:","},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_JIS_KeypadComma,
+             modifiers:{numericKeyPadKey:1, metaKey:1}, chars:",", unmodifiedChars:","},
             nsIDOMKeyEvent.DOM_VK_SEPARATOR, ",", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
 
     // French, numeric
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_1, chars:"\u0026", unmodifiedChars:"\u0026"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_1,
+             modifiers:{}, chars:"\u0026", unmodifiedChars:"\u0026"},
             nsIDOMKeyEvent.DOM_VK_1, "\u0026", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_1, shift:1, chars:"1", unmodifiedChars:"1"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_1,
+             modifiers:{shiftKey:1}, chars:"1", unmodifiedChars:"1"},
+            nsIDOMKeyEvent.DOM_VK_1, "1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_1,
+             modifiers:{ctrlKey:1}, chars:"1", unmodifiedChars:"\u0026"},
             nsIDOMKeyEvent.DOM_VK_1, "1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_1, ctrl:1, chars:"1", unmodifiedChars:"\u0026"},
-            nsIDOMKeyEvent.DOM_VK_1, "1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_1, command:1, chars:"\u0026", unmodifiedChars:"\u0026"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_1,
+             modifiers:{metaKey:1}, chars:"\u0026", unmodifiedChars:"\u0026"},
+            nsIDOMKeyEvent.DOM_VK_1, "\u0026", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_1,
+             modifiers:{metaKey:1, shiftKey:1}, chars:"1", unmodifiedChars:"1"},
             nsIDOMKeyEvent.DOM_VK_1, "1", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_2, chars:"\u00E9", unmodifiedChars:"\u00E9"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_2,
+             modifiers:{}, chars:"\u00E9", unmodifiedChars:"\u00E9"},
             nsIDOMKeyEvent.DOM_VK_2, "\u00E9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_2, shift:1, chars:"2", unmodifiedChars:"2"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_2,
+             modifiers:{shiftKey:1}, chars:"2", unmodifiedChars:"2"},
+            nsIDOMKeyEvent.DOM_VK_2, "2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_2,
+             modifiers:{ctrlKey:1}, chars:"2", unmodifiedChars:"\u00E9"},
             nsIDOMKeyEvent.DOM_VK_2, "2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_2, ctrl:1, chars:"2", unmodifiedChars:"\u00E9"},
-            nsIDOMKeyEvent.DOM_VK_2, "2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_2, command:1, chars:"\u00E9", unmodifiedChars:"\u00E9"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_2,
+             modifiers:{metaKey:1}, chars:"\u00E9", unmodifiedChars:"\u00E9"},
+            nsIDOMKeyEvent.DOM_VK_2, "\u00E9", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_2,
+             modifiers:{metaKey:1, shiftKey:1}, chars:"2", unmodifiedChars:"2"},
             nsIDOMKeyEvent.DOM_VK_2, "2", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_3, chars:"\"", unmodifiedChars:"\""},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_3,
+             modifiers:{}, chars:"\"", unmodifiedChars:"\""},
             nsIDOMKeyEvent.DOM_VK_3, "\"", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_3, shift:1, chars:"3", unmodifiedChars:"3"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_3,
+             modifiers:{shiftKey:1}, chars:"3", unmodifiedChars:"3"},
             nsIDOMKeyEvent.DOM_VK_3, "3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_3, ctrl:1, chars:"3", unmodifiedChars:"\""},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_3,
+             modifiers:{ctrlKey:1}, chars:"3", unmodifiedChars:"\""},
             nsIDOMKeyEvent.DOM_VK_3, "3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_3, command:1, chars:"\"", unmodifiedChars:"\""},
-            nsIDOMKeyEvent.DOM_VK_3, "3", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_4, chars:"'", unmodifiedChars:"'"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_3,
+             modifiers:{metaKey:1}, chars:"\"", unmodifiedChars:"\""},
+            nsIDOMKeyEvent.DOM_VK_3, "\"", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
+    // Cmd+Shift+3 is a shortcut key of taking a snapshot
+    // testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_3,
+    //          modifiers:{metaKey:1, shiftKey:1}, chars:"\"", unmodifiedChars:"\""},
+    //         nsIDOMKeyEvent.DOM_VK_3, "3", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_4,
+             modifiers:{}, chars:"'", unmodifiedChars:"'"},
             nsIDOMKeyEvent.DOM_VK_4, "'", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_4, shift:1, chars:"4", unmodifiedChars:"4"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_4,
+             modifiers:{shiftKey:1}, chars:"4", unmodifiedChars:"4"},
             nsIDOMKeyEvent.DOM_VK_4, "4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_4, ctrl:1, chars:"4", unmodifiedChars:"'"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_4,
+             modifiers:{ctrlKey:1}, chars:"4", unmodifiedChars:"'"},
             nsIDOMKeyEvent.DOM_VK_4, "4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_4, command:1, chars:"'", unmodifiedChars:"'"},
-            nsIDOMKeyEvent.DOM_VK_4, "4", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_5, chars:"(", unmodifiedChars:"("},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_4,
+             modifiers:{metaKey:1}, chars:"'", unmodifiedChars:"'"},
+            nsIDOMKeyEvent.DOM_VK_4, "'", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
+    // Cmd+Shift+4 is a shortcut key of taking a snapshot in specific range
+    // testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_4,
+    //          modifiers:{metaKey:1, shiftKey:1}, chars:"4", unmodifiedChars:"4"},
+    //         nsIDOMKeyEvent.DOM_VK_4, "4", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_5,
+             modifiers:{}, chars:"(", unmodifiedChars:"("},
             nsIDOMKeyEvent.DOM_VK_5, "(", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_5, shift:1, chars:"5", unmodifiedChars:"5"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_5,
+             modifiers:{shiftKey:1}, chars:"5", unmodifiedChars:"5"},
             nsIDOMKeyEvent.DOM_VK_5, "5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_5, ctrl:1, chars:"5", unmodifiedChars:"("},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_5,
+             modifiers:{ctrlKey:1}, chars:"5", unmodifiedChars:"("},
             nsIDOMKeyEvent.DOM_VK_5, "5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_5, command:1, chars:"(", unmodifiedChars:"("},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_5,
+             modifiers:{metaKey:1}, chars:"(", unmodifiedChars:"("},
+            nsIDOMKeyEvent.DOM_VK_5, "(", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_5,
+             modifiers:{metaKey:1, shiftKey:1}, chars:"5", unmodifiedChars:"5"},
             nsIDOMKeyEvent.DOM_VK_5, "5", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_6, chars:"\u00A7", unmodifiedChars:"\u00A7"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_6,
+             modifiers:{}, chars:"\u00A7", unmodifiedChars:"\u00A7"},
             nsIDOMKeyEvent.DOM_VK_6, "\u00A7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_6, shift:1, chars:"6", unmodifiedChars:"6"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_6,
+             modifiers:{shiftKey:1}, chars:"6", unmodifiedChars:"6"},
             nsIDOMKeyEvent.DOM_VK_6, "6", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // TODO:
-    // testKey({layout:"French", keyCode:MAC_VK_ANSI_6, ctrl:1, chars:"\u001D", unmodifiedChars:"\u00A7"},
+    // testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_6,
+    //          modifiers:{ctrlKey:1}, chars:"\u001D", unmodifiedChars:"\u00A7"},
     //         nsIDOMKeyEvent.DOM_VK_6, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // Ctrl+6 sets strange char
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_6, command:1, chars:"\u00A7", unmodifiedChars:"\u00A7"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_6,
+             modifiers:{metaKey:1}, chars:"\u00A7", unmodifiedChars:"\u00A7"},
+            nsIDOMKeyEvent.DOM_VK_6, "\u00A7", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_6,
+             modifiers:{metaKey:1, shiftKey:1}, chars:"6", unmodifiedChars:"6"},
             nsIDOMKeyEvent.DOM_VK_6, "6", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_7, chars:"\u00E8", unmodifiedChars:"\u00E8"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_7,
+             modifiers:{}, chars:"\u00E8", unmodifiedChars:"\u00E8"},
             nsIDOMKeyEvent.DOM_VK_7, "\u00E8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_7, shift:1, chars:"7", unmodifiedChars:"7"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_7,
+             modifiers:{shiftKey:1}, chars:"7", unmodifiedChars:"7"},
+            nsIDOMKeyEvent.DOM_VK_7, "7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_7,
+             modifiers:{ctrlKey:1}, chars:"7", unmodifiedChars:"\u00E8"},
             nsIDOMKeyEvent.DOM_VK_7, "7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_7, ctrl:1, chars:"7", unmodifiedChars:"\u00E8"},
-            nsIDOMKeyEvent.DOM_VK_7, "7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_7, command:1, chars:"\u00E8", unmodifiedChars:"\u00E8"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_7,
+             modifiers:{metaKey:1}, chars:"\u00E8", unmodifiedChars:"\u00E8"},
+            nsIDOMKeyEvent.DOM_VK_7, "\u00E8", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_7,
+             modifiers:{metaKey:1, shiftKey:1}, chars:"7", unmodifiedChars:"7"},
             nsIDOMKeyEvent.DOM_VK_7, "7", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_8, chars:"!", unmodifiedChars:"!"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_8,
+             modifiers:{}, chars:"!", unmodifiedChars:"!"},
             nsIDOMKeyEvent.DOM_VK_8, "!", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_8, shift:1, chars:"8", unmodifiedChars:"8"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_8,
+             modifiers:{shiftKey:1}, chars:"8", unmodifiedChars:"8"},
             nsIDOMKeyEvent.DOM_VK_8, "8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_8, ctrl:1, chars:"8", unmodifiedChars:"!"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_8,
+             modifiers:{ctrlKey:1}, chars:"8", unmodifiedChars:"!"},
             nsIDOMKeyEvent.DOM_VK_8, "8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_8, command:1, chars:"!", unmodifiedChars:"!"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_8,
+             modifiers:{metaKey:1}, chars:"!", unmodifiedChars:"!"},
+            nsIDOMKeyEvent.DOM_VK_8, "!", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_8,
+             modifiers:{metaKey:1, shiftKey:1}, chars:"8", unmodifiedChars:"8"},
             nsIDOMKeyEvent.DOM_VK_8, "8", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_9, chars:"\u00E7", unmodifiedChars:"\u00E7"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_9,
+             modifiers:{}, chars:"\u00E7", unmodifiedChars:"\u00E7"},
             nsIDOMKeyEvent.DOM_VK_9, "\u00E7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_9, shift:1, chars:"9", unmodifiedChars:"9"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_9,
+             modifiers:{shiftKey:1}, chars:"9", unmodifiedChars:"9"},
             nsIDOMKeyEvent.DOM_VK_9, "9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // TODO:
-    // testKey({layout:"French", keyCode:MAC_VK_ANSI_9, ctrl:1, chars:"\u001C", unmodifiedChars:"\u00E7"},
+    // testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_9,
+    //          modifiers:{ctrlKey:1}, chars:"\u001C", unmodifiedChars:"\u00E7"},
     //         nsIDOMKeyEvent.DOM_VK_9, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // Ctrl+9 sets strange char
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_9, command:1, chars:"\u00E7", unmodifiedChars:"\u00E7"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_9,
+             modifiers:{metaKey:1}, chars:"\u00E7", unmodifiedChars:"\u00E7"},
+            nsIDOMKeyEvent.DOM_VK_9, "\u00E7", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_9,
+             modifiers:{metaKey:1, shiftKey:1}, chars:"9", unmodifiedChars:"9"},
             nsIDOMKeyEvent.DOM_VK_9, "9", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_0, chars:"\u00E0", unmodifiedChars:"\u00E0"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_0,
+             modifiers:{}, chars:"\u00E0", unmodifiedChars:"\u00E0"},
             nsIDOMKeyEvent.DOM_VK_0, "\u00E0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_0, shift:1, chars:"0", unmodifiedChars:"0"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_0,
+             modifiers:{shiftKey:1}, chars:"0", unmodifiedChars:"0"},
             nsIDOMKeyEvent.DOM_VK_0, "0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // XXX No events fired, not sure the reason.
-    // testKey({layout:"French", keyCode:MAC_VK_ANSI_0, ctrl:1, chars:"", unmodifiedChars:"\u00E0"},
+    // testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_0,
+    //          modifiers:{ctrlKey:1}, chars:"", unmodifiedChars:"\u00E0"},
     //         nsIDOMKeyEvent.DOM_VK_0, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:MAC_VK_ANSI_0, command:1, chars:"\u00E0", unmodifiedChars:"\u00E0"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_0,
+             modifiers:{metaKey:1}, chars:"\u00E0", unmodifiedChars:"\u00E0"},
+            nsIDOMKeyEvent.DOM_VK_0, "\u00E0", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:MAC_VK_ANSI_0,
+             modifiers:{metaKey:1, shiftKey:1}, chars:"0", unmodifiedChars:"0"},
             nsIDOMKeyEvent.DOM_VK_0, "0", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Thai
     // keycode should be DOM_VK_[A-Z] of the key on the latest ASCII capable keyboard layout is for alphabet
-    testKey({layout:"Thai", keyCode:MAC_VK_ANSI_A, chars:"\u0E1F", unmodifiedChars:"\u0E1F"},
+    testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_A,
+             modifiers:{}, chars:"\u0E1F", unmodifiedChars:"\u0E1F"},
             nsIDOMKeyEvent.DOM_VK_A, "\u0E1F", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // keycode should be shifted character if unshifted character isn't an ASCII character
-    testKey({layout:"Thai", keyCode:MAC_VK_ANSI_Quote, chars:"\u0E07", unmodifiedChars:"\u0E07"},
+    testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_Quote,
+             modifiers:{}, chars:"\u0E07", unmodifiedChars:"\u0E07"},
             nsIDOMKeyEvent.DOM_VK_PERIOD, "\u0E07", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // keycode should be zero if the character of the key on the latest ASCII capable keyboard layout isn't for alphabet
-    testKey({layout:"Thai", keyCode:MAC_VK_ANSI_Period, chars:"\u0E43", unmodifiedChars:"\u0E43"},
+    testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_Period,
+             modifiers:{}, chars:"\u0E43", unmodifiedChars:"\u0E43"},
             0, "\u0E43", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // keycode should be DOM_VK_[0-9] if the key on the latest ASCII capable keyboard layout is for numeric
-    testKey({layout:"Thai", keyCode:MAC_VK_ANSI_1, chars:"\u0E45", unmodifiedChars:"\u0E45"},
+    testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_1,
+             modifiers:{}, chars:"\u0E45", unmodifiedChars:"\u0E45"},
             nsIDOMKeyEvent.DOM_VK_1, "\u0E45", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Thai", keyCode:MAC_VK_ANSI_2, chars:"/", unmodifiedChars:"/"},
+    testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_2,
+             modifiers:{}, chars:"/", unmodifiedChars:"/"},
             nsIDOMKeyEvent.DOM_VK_2, "/", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Thai", keyCode:MAC_VK_ANSI_3, chars:"_", unmodifiedChars:"_"},
+    testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_3,
+             modifiers:{}, chars:"_", unmodifiedChars:"_"},
             nsIDOMKeyEvent.DOM_VK_3, "_", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Thai", keyCode:MAC_VK_ANSI_4, chars:"\u0E20", unmodifiedChars:"\u0E20"},
+    testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_4,
+             modifiers:{}, chars:"\u0E20", unmodifiedChars:"\u0E20"},
             nsIDOMKeyEvent.DOM_VK_4, "\u0E20", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Thai", keyCode:MAC_VK_ANSI_5, chars:"\u0E16", unmodifiedChars:"\u0E16"},
+    testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_5,
+             modifiers:{}, chars:"\u0E16", unmodifiedChars:"\u0E16"},
             nsIDOMKeyEvent.DOM_VK_5, "\u0E16", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Thai", keyCode:MAC_VK_ANSI_6, chars:"\u0E38", unmodifiedChars:"\u0E38"},
+    testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_6,
+             modifiers:{}, chars:"\u0E38", unmodifiedChars:"\u0E38"},
             nsIDOMKeyEvent.DOM_VK_6, "\u0E38", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Thai", keyCode:MAC_VK_ANSI_7, chars:"\u0E36", unmodifiedChars:"\u0E36"},
+    testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_7,
+             modifiers:{}, chars:"\u0E36", unmodifiedChars:"\u0E36"},
             nsIDOMKeyEvent.DOM_VK_7, "\u0E36", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Thai", keyCode:MAC_VK_ANSI_8, chars:"\u0E04", unmodifiedChars:"\u0E04"},
+    testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_8,
+             modifiers:{}, chars:"\u0E04", unmodifiedChars:"\u0E04"},
             nsIDOMKeyEvent.DOM_VK_8, "\u0E04", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Thai", keyCode:MAC_VK_ANSI_9, chars:"\u0E15", unmodifiedChars:"\u0E15"},
+    testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_9,
+             modifiers:{}, chars:"\u0E15", unmodifiedChars:"\u0E15"},
             nsIDOMKeyEvent.DOM_VK_9, "\u0E15", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Thai", keyCode:MAC_VK_ANSI_0, chars:"\u0E08", unmodifiedChars:"\u0E08"},
+    testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:MAC_VK_ANSI_0,
+             modifiers:{}, chars:"\u0E08", unmodifiedChars:"\u0E08"},
             nsIDOMKeyEvent.DOM_VK_0, "\u0E08", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Dvorak-Qwerty, layout should be changed when Command key is pressed.
-    testKey({layout:"Dvorak-Qwerty", keyCode:MAC_VK_ANSI_S, chars:"o", unmodifiedChars:"o"},
+    testKey({layout:KEYBOARD_LAYOUT_DVORAK_QWERTY, keyCode:MAC_VK_ANSI_S,
+             modifiers:{}, chars:"o", unmodifiedChars:"o"},
             nsIDOMKeyEvent.DOM_VK_O, "o", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Dvorak-Qwerty", keyCode:MAC_VK_ANSI_S, shift:1, chars:"O", unmodifiedChars:"O"},
+    testKey({layout:KEYBOARD_LAYOUT_DVORAK_QWERTY, keyCode:MAC_VK_ANSI_S,
+             modifiers:{shiftKey:1}, chars:"O", unmodifiedChars:"O"},
             nsIDOMKeyEvent.DOM_VK_O, "O", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Dvorak-Qwerty", keyCode:MAC_VK_ANSI_S, ctrl:1, chars:"\u000F", unmodifiedChars:"o"},
+    testKey({layout:KEYBOARD_LAYOUT_DVORAK_QWERTY, keyCode:MAC_VK_ANSI_S,
+             modifiers:{ctrlKey:1}, chars:"\u000F", unmodifiedChars:"o"},
             nsIDOMKeyEvent.DOM_VK_O, "o", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Dvorak-Qwerty", keyCode:MAC_VK_ANSI_S, alt:1, chars:"\u00F8", unmodifiedChars:"o"},
+    testKey({layout:KEYBOARD_LAYOUT_DVORAK_QWERTY, keyCode:MAC_VK_ANSI_S,
+             modifiers:{altKey:1}, chars:"\u00F8", unmodifiedChars:"o"},
             nsIDOMKeyEvent.DOM_VK_O, "\u00F8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Dvorak-Qwerty", keyCode:MAC_VK_ANSI_S, command:1, chars:"s", unmodifiedChars:"o"},
+    testKey({layout:KEYBOARD_LAYOUT_DVORAK_QWERTY, keyCode:MAC_VK_ANSI_S,
+             modifiers:{metaKey:1}, chars:"s", unmodifiedChars:"o"},
             nsIDOMKeyEvent.DOM_VK_S, "s", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Dvorak-Qwerty", keyCode:MAC_VK_ANSI_D, chars:"e", unmodifiedChars:"e"},
+    testKey({layout:KEYBOARD_LAYOUT_DVORAK_QWERTY, keyCode:MAC_VK_ANSI_D,
+             modifiers:{}, chars:"e", unmodifiedChars:"e"},
             nsIDOMKeyEvent.DOM_VK_E, "e", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Dvorak-Qwerty", keyCode:MAC_VK_ANSI_D, shift:1, chars:"E", unmodifiedChars:"E"},
+    testKey({layout:KEYBOARD_LAYOUT_DVORAK_QWERTY, keyCode:MAC_VK_ANSI_D,
+             modifiers:{shiftKey:1}, chars:"E", unmodifiedChars:"E"},
             nsIDOMKeyEvent.DOM_VK_E, "E", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Dvorak-Qwerty", keyCode:MAC_VK_ANSI_D, ctrl:1, chars:"\u0005", unmodifiedChars:"e"},
+    testKey({layout:KEYBOARD_LAYOUT_DVORAK_QWERTY, keyCode:MAC_VK_ANSI_D,
+             modifiers:{ctrlKey:1}, chars:"\u0005", unmodifiedChars:"e"},
             nsIDOMKeyEvent.DOM_VK_E, "e", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Dvorak-Qwerty", keyCode:MAC_VK_ANSI_D, alt:1, chars:"", unmodifiedChars:"e"},
+    testKey({layout:KEYBOARD_LAYOUT_DVORAK_QWERTY, keyCode:MAC_VK_ANSI_D,
+             modifiers:{altKey:1}, chars:"", unmodifiedChars:"e"},
             nsIDOMKeyEvent.DOM_VK_E, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // dead key
-    testKey({layout:"Dvorak-Qwerty", keyCode:MAC_VK_ANSI_D, command:1, chars:"d", unmodifiedChars:"e"},
+    testKey({layout:KEYBOARD_LAYOUT_DVORAK_QWERTY, keyCode:MAC_VK_ANSI_D,
+             modifiers:{metaKey:1}, chars:"d", unmodifiedChars:"e"},
             nsIDOMKeyEvent.DOM_VK_D, "d", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Dvorak-Qwerty", keyCode:MAC_VK_ANSI_I, command:1, alt:1, chars:"^", unmodifiedChars:"c"},
+    testKey({layout:KEYBOARD_LAYOUT_DVORAK_QWERTY, keyCode:MAC_VK_ANSI_I,
+             modifiers:{metaKey:1, altKey:1}, chars:"^", unmodifiedChars:"c"},
             nsIDOMKeyEvent.DOM_VK_I, "^", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Dvorak-Qwerty", keyCode:MAC_VK_ANSI_I, command:1, alt:1, shift:1, chars:"\u02C6", unmodifiedChars:"C"},
-            nsIDOMKeyEvent.DOM_VK_I, "\u02C6", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);  }
-  else if (IS_WIN) {
+    testKey({layout:KEYBOARD_LAYOUT_DVORAK_QWERTY, keyCode:MAC_VK_ANSI_I,
+             modifiers:{metaKey:1, altKey:1, shiftKey:1}, chars:"\u02C6", unmodifiedChars:"C"},
+            nsIDOMKeyEvent.DOM_VK_I, "\u02C6", SHOULD_DELIVER_KEYDOWN_KEYPRESS, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
+  } else if (IS_WIN) {
     // On Windows, you can use Spy++ or Winspector (free) to watch window messages.
     // The keyCode is given by the wParam of the last WM_KEYDOWN message. The
     // chars string is given by the wParam of the WM_CHAR message. unmodifiedChars
     // is not needed on Windows.
 
     // Plain text input
-    testKey({layout:"US", keyCode:WIN_VK_A, chars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_A,
+             modifiers:{}, chars:"a"},
             nsIDOMKeyEvent.DOM_VK_A, "a", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_B, chars:"b"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_B,
+             modifiers:{}, chars:"b"},
             nsIDOMKeyEvent.DOM_VK_B, "b", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_A, shift:1, chars:"A"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_A,
+             modifiers:{shiftKey:1}, chars:"A"},
             nsIDOMKeyEvent.DOM_VK_A, "A", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Ctrl keys
-    testKey({layout:"US", keyCode:WIN_VK_A, ctrl:1, chars:"\u0001"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_A,
+             modifiers:{ctrlKey:1}, chars:"\u0001"},
             nsIDOMKeyEvent.DOM_VK_A, "a", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_A, ctrl:1, shift:1, chars:"\u0001"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_A,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:"\u0001"},
             nsIDOMKeyEvent.DOM_VK_A, "A", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Alt keys
-    testKey({layout:"US", keyCode:WIN_VK_A, alt:1, chars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_A,
+             modifiers:{altKey:1}, chars:"a"},
             nsIDOMKeyEvent.DOM_VK_A, "a", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_A, alt:1, shift:1, chars:"A"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_A,
+             modifiers:{altKey:1, shiftKey:1}, chars:"A"},
             nsIDOMKeyEvent.DOM_VK_A, "A", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Shift-ctrl-alt generates no WM_CHAR, but we still get a keypress
-    testKey({layout:"US", keyCode:WIN_VK_A, alt:1, ctrl:1, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_A,
+             modifiers:{altKey:1, ctrlKey:1, shiftKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_A, "A", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Greek plain text
-    testKey({layout:"Greek", keyCode:WIN_VK_A, chars:"\u03b1"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:WIN_VK_A,
+             modifiers:{}, chars:"\u03b1"},
             nsIDOMKeyEvent.DOM_VK_A, "\u03b1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Greek", keyCode:WIN_VK_A, shift:1, chars:"\u0391"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:WIN_VK_A,
+             modifiers:{shiftKey:1}, chars:"\u0391"},
             nsIDOMKeyEvent.DOM_VK_A, "\u0391", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Greek ctrl keys produce Latin charcodes
-    testKey({layout:"Greek", keyCode:WIN_VK_A, ctrl:1, chars:"\u0001"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:WIN_VK_A,
+             modifiers:{ctrlKey:1}, chars:"\u0001"},
             nsIDOMKeyEvent.DOM_VK_A, "a", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Greek", keyCode:WIN_VK_A, ctrl:1, shift:1, chars:"\u0001"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:WIN_VK_A,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:"\u0001"},
             nsIDOMKeyEvent.DOM_VK_A, "A", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Caps Lock key event
-    testKey({layout:"US", keyCode:WIN_VK_CAPITAL, capsLock:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_CAPITAL,
+             modifiers:{capsLockKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_CAPS_LOCK, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_CAPITAL, capsLock:0, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_CAPITAL,
+             modifiers:{capsLockKey:0}, chars:""},
             nsIDOMKeyEvent.DOM_VK_CAPS_LOCK, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Shift keys
-    testKey({layout:"US", keyCode:WIN_VK_LSHIFT, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_LSHIFT,
+             modifiers:{shiftKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_SHIFT, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_LEFT);
-    testKey({layout:"US", keyCode:WIN_VK_RSHIFT, shiftRight:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_RSHIFT,
+             modifiers:{shiftRightKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_SHIFT, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_RIGHT);
 
     // Ctrl keys
-    testKey({layout:"US", keyCode:WIN_VK_LCONTROL, ctrl:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_LCONTROL,
+             modifiers:{ctrlKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_CONTROL, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_LEFT);
-    testKey({layout:"US", keyCode:WIN_VK_RCONTROL, ctrlRight:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_RCONTROL,
+             modifiers:{ctrlRightKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_CONTROL, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_RIGHT);
 
     // Alt keys
-    testKey({layout:"US", keyCode:WIN_VK_LMENU, alt:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_LMENU,
+             modifiers:{altKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_ALT, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_LEFT);
-    testKey({layout:"US", keyCode:WIN_VK_RMENU, altRight:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_RMENU,
+             modifiers:{altRightKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_ALT, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_RIGHT);
 
     // Win keys
-    testKey({layout:"US", keyCode:WIN_VK_LWIN, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_LWIN,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_WIN, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_LEFT);
-    testKey({layout:"US", keyCode:WIN_VK_RWIN, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_RWIN,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_WIN, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_RIGHT);
 
     // all keys on keyboard (keyCode test)
-    testKey({layout:"US", keyCode:WIN_VK_BACK, chars:"\u0008"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_BACK,
+             modifiers:{}, chars:"\u0008"},
             nsIDOMKeyEvent.DOM_VK_BACK_SPACE, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_TAB, chars:"\t"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_TAB,
+             modifiers:{}, chars:"\t"},
             nsIDOMKeyEvent.DOM_VK_TAB, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_RETURN, chars:"\r"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_RETURN,
+             modifiers:{}, chars:"\r"},
             nsIDOMKeyEvent.DOM_VK_RETURN, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_PAUSE, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_PAUSE,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_PAUSE, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_KANA, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_KANA,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_KANA, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_JUNJA, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_JUNJA,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_JUNJA, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_FINAL, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_FINAL,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_FINAL, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_KANJI, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_KANJI,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_KANJI, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_ESCAPE, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_ESCAPE,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_ESCAPE, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_CONVERT, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_CONVERT,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_CONVERT, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_NONCONVERT, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_NONCONVERT,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_NONCONVERT, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_ACCEPT, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_ACCEPT,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_ACCEPT, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_MODECHANGE, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_MODECHANGE,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_MODECHANGE, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_SPACE, chars:" "},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_SPACE,
+             modifiers:{}, chars:" "},
             nsIDOMKeyEvent.DOM_VK_SPACE, " ", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_SELECT, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_SELECT,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_SELECT, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_PRINT, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_PRINT,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_PRINT, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_EXECUTE, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_EXECUTE,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_EXECUTE, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_SNAPSHOT, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_SNAPSHOT,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_PRINTSCREEN, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_HELP, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_HELP,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_HELP, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_SLEEP, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_SLEEP,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_SLEEP, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
     // XXX TODO: we cannot test Home, Up, PageUp, Left, Right, End, Down, PageDown, Ins and Del.
 
     // US
     // Alphabet
-    testKey({layout:"US", keyCode:WIN_VK_A, chars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_A,
+             modifiers:{}, chars:"a"},
             nsIDOMKeyEvent.DOM_VK_A, "a", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_A, shift:1, chars:"A"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_A,
+             modifiers:{shiftKey:1}, chars:"A"},
             nsIDOMKeyEvent.DOM_VK_A, "A", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_B, chars:"b"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_B,
+             modifiers:{}, chars:"b"},
             nsIDOMKeyEvent.DOM_VK_B, "b", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_B, shift:1, chars:"B"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_B,
+             modifiers:{shiftKey:1}, chars:"B"},
             nsIDOMKeyEvent.DOM_VK_B, "B", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_C, chars:"c"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_C,
+             modifiers:{}, chars:"c"},
             nsIDOMKeyEvent.DOM_VK_C, "c", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_C, shift:1, chars:"C"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_C,
+             modifiers:{shiftKey:1}, chars:"C"},
             nsIDOMKeyEvent.DOM_VK_C, "C", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_D, chars:"d"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_D,
+             modifiers:{}, chars:"d"},
             nsIDOMKeyEvent.DOM_VK_D, "d", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_D, shift:1, chars:"D"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_D,
+             modifiers:{shiftKey:1}, chars:"D"},
             nsIDOMKeyEvent.DOM_VK_D, "D", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_E, chars:"e"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_E,
+             modifiers:{}, chars:"e"},
             nsIDOMKeyEvent.DOM_VK_E, "e", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_E, shift:1, chars:"E"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_E,
+             modifiers:{shiftKey:1}, chars:"E"},
             nsIDOMKeyEvent.DOM_VK_E, "E", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_F, chars:"f"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_F,
+             modifiers:{}, chars:"f"},
             nsIDOMKeyEvent.DOM_VK_F, "f", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_F, shift:1, chars:"F"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_F,
+             modifiers:{shiftKey:1}, chars:"F"},
             nsIDOMKeyEvent.DOM_VK_F, "F", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_G, chars:"g"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_G,
+             modifiers:{}, chars:"g"},
             nsIDOMKeyEvent.DOM_VK_G, "g", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_G, shift:1, chars:"G"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_G,
+             modifiers:{shiftKey:1}, chars:"G"},
             nsIDOMKeyEvent.DOM_VK_G, "G", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_H, chars:"h"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_H,
+             modifiers:{}, chars:"h"},
             nsIDOMKeyEvent.DOM_VK_H, "h", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_H, shift:1, chars:"H"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_H,
+             modifiers:{shiftKey:1}, chars:"H"},
             nsIDOMKeyEvent.DOM_VK_H, "H", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_I, chars:"i"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_I,
+             modifiers:{}, chars:"i"},
             nsIDOMKeyEvent.DOM_VK_I, "i", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_I, shift:1, chars:"I"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_I,
+             modifiers:{shiftKey:1}, chars:"I"},
             nsIDOMKeyEvent.DOM_VK_I, "I", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_J, chars:"j"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_J,
+             modifiers:{}, chars:"j"},
             nsIDOMKeyEvent.DOM_VK_J, "j", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_J, shift:1, chars:"J"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_J,
+             modifiers:{shiftKey:1}, chars:"J"},
             nsIDOMKeyEvent.DOM_VK_J, "J", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_K, chars:"k"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_K,
+             modifiers:{}, chars:"k"},
             nsIDOMKeyEvent.DOM_VK_K, "k", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_K, shift:1, chars:"K"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_K,
+             modifiers:{shiftKey:1}, chars:"K"},
             nsIDOMKeyEvent.DOM_VK_K, "K", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_L, chars:"l"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_L,
+             modifiers:{}, chars:"l"},
             nsIDOMKeyEvent.DOM_VK_L, "l", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_L, shift:1, chars:"L"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_L,
+             modifiers:{shiftKey:1}, chars:"L"},
             nsIDOMKeyEvent.DOM_VK_L, "L", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_M, chars:"m"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_M,
+             modifiers:{}, chars:"m"},
             nsIDOMKeyEvent.DOM_VK_M, "m", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_M, shift:1, chars:"M"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_M,
+             modifiers:{shiftKey:1}, chars:"M"},
             nsIDOMKeyEvent.DOM_VK_M, "M", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_N, chars:"n"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_N,
+             modifiers:{}, chars:"n"},
             nsIDOMKeyEvent.DOM_VK_N, "n", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_N, shift:1, chars:"N"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_N,
+             modifiers:{shiftKey:1}, chars:"N"},
             nsIDOMKeyEvent.DOM_VK_N, "N", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_O, chars:"o"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_O,
+             modifiers:{}, chars:"o"},
             nsIDOMKeyEvent.DOM_VK_O, "o", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_O, shift:1, chars:"O"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_O,
+             modifiers:{shiftKey:1}, chars:"O"},
             nsIDOMKeyEvent.DOM_VK_O, "O", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_P, chars:"p"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_P,
+             modifiers:{}, chars:"p"},
             nsIDOMKeyEvent.DOM_VK_P, "p", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_P, shift:1, chars:"P"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_P,
+             modifiers:{shiftKey:1}, chars:"P"},
             nsIDOMKeyEvent.DOM_VK_P, "P", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_Q, chars:"q"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_Q,
+             modifiers:{}, chars:"q"},
             nsIDOMKeyEvent.DOM_VK_Q, "q", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_Q, shift:1, chars:"Q"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_Q,
+             modifiers:{shiftKey:1}, chars:"Q"},
             nsIDOMKeyEvent.DOM_VK_Q, "Q", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_R, chars:"r"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_R,
+             modifiers:{}, chars:"r"},
             nsIDOMKeyEvent.DOM_VK_R, "r", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_R, shift:1, chars:"R"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_R,
+             modifiers:{shiftKey:1}, chars:"R"},
             nsIDOMKeyEvent.DOM_VK_R, "R", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_S, chars:"s"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_S,
+             modifiers:{}, chars:"s"},
             nsIDOMKeyEvent.DOM_VK_S, "s", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_S, shift:1, chars:"S"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_S,
+             modifiers:{shiftKey:1}, chars:"S"},
             nsIDOMKeyEvent.DOM_VK_S, "S", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_T, chars:"t"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_T,
+             modifiers:{}, chars:"t"},
             nsIDOMKeyEvent.DOM_VK_T, "t", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_T, shift:1, chars:"T"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_T,
+             modifiers:{shiftKey:1}, chars:"T"},
             nsIDOMKeyEvent.DOM_VK_T, "T", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_U, chars:"u"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_U,
+             modifiers:{}, chars:"u"},
             nsIDOMKeyEvent.DOM_VK_U, "u", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_U, shift:1, chars:"U"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_U,
+             modifiers:{shiftKey:1}, chars:"U"},
             nsIDOMKeyEvent.DOM_VK_U, "U", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_V, chars:"v"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_V,
+             modifiers:{}, chars:"v"},
             nsIDOMKeyEvent.DOM_VK_V, "v", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_V, shift:1, chars:"V"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_V,
+             modifiers:{shiftKey:1}, chars:"V"},
             nsIDOMKeyEvent.DOM_VK_V, "V", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_W, chars:"w"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_W,
+             modifiers:{}, chars:"w"},
             nsIDOMKeyEvent.DOM_VK_W, "w", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_W, shift:1, chars:"W"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_W,
+             modifiers:{shiftKey:1}, chars:"W"},
             nsIDOMKeyEvent.DOM_VK_W, "W", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_X, chars:"x"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_X,
+             modifiers:{}, chars:"x"},
             nsIDOMKeyEvent.DOM_VK_X, "x", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_X, shift:1, chars:"X"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_X,
+             modifiers:{shiftKey:1}, chars:"X"},
             nsIDOMKeyEvent.DOM_VK_X, "X", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_Y, chars:"y"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_Y,
+             modifiers:{}, chars:"y"},
             nsIDOMKeyEvent.DOM_VK_Y, "y", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_Y, shift:1, chars:"Y"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_Y,
+             modifiers:{shiftKey:1}, chars:"Y"},
             nsIDOMKeyEvent.DOM_VK_Y, "Y", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_Z, chars:"z"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_Z,
+             modifiers:{}, chars:"z"},
             nsIDOMKeyEvent.DOM_VK_Z, "z", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_Z, shift:1, chars:"Z"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_Z,
+             modifiers:{shiftKey:1}, chars:"Z"},
             nsIDOMKeyEvent.DOM_VK_Z, "Z", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Numeric
-    testKey({layout:"US", keyCode:WIN_VK_0, chars:"0"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_0,
+             modifiers:{}, chars:"0"},
             nsIDOMKeyEvent.DOM_VK_0, "0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_0, shift:1, chars:")"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_0,
+             modifiers:{shiftKey:1}, chars:")"},
             nsIDOMKeyEvent.DOM_VK_0, ")", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_1, chars:"1"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_1,
+             modifiers:{}, chars:"1"},
             nsIDOMKeyEvent.DOM_VK_1, "1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_1, shift:1, chars:"!"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_1,
+             modifiers:{shiftKey:1}, chars:"!"},
             nsIDOMKeyEvent.DOM_VK_1, "!", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_2, chars:"2"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_2,
+             modifiers:{}, chars:"2"},
             nsIDOMKeyEvent.DOM_VK_2, "2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_2, shift:1, chars:"@"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_2,
+             modifiers:{shiftKey:1}, chars:"@"},
             nsIDOMKeyEvent.DOM_VK_2, "@", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_3, chars:"3"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_3,
+             modifiers:{}, chars:"3"},
             nsIDOMKeyEvent.DOM_VK_3, "3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_3, shift:1, chars:"#"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_3,
+             modifiers:{shiftKey:1}, chars:"#"},
             nsIDOMKeyEvent.DOM_VK_3, "#", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_4, chars:"4"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_4,
+             modifiers:{}, chars:"4"},
             nsIDOMKeyEvent.DOM_VK_4, "4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_4, shift:1, chars:"$"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_4,
+             modifiers:{shiftKey:1}, chars:"$"},
             nsIDOMKeyEvent.DOM_VK_4, "$", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_5, chars:"5"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_5,
+             modifiers:{}, chars:"5"},
             nsIDOMKeyEvent.DOM_VK_5, "5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_5, shift:1, chars:"%"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_5,
+             modifiers:{shiftKey:1}, chars:"%"},
             nsIDOMKeyEvent.DOM_VK_5, "%", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_6, chars:"6"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_6,
+             modifiers:{}, chars:"6"},
             nsIDOMKeyEvent.DOM_VK_6, "6", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_6, shift:1, chars:"^"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_6,
+             modifiers:{shiftKey:1}, chars:"^"},
             nsIDOMKeyEvent.DOM_VK_6, "^", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_7, chars:"7"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_7,
+             modifiers:{}, chars:"7"},
             nsIDOMKeyEvent.DOM_VK_7, "7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_7, shift:1, chars:"&"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_7,
+             modifiers:{shiftKey:1}, chars:"&"},
             nsIDOMKeyEvent.DOM_VK_7, "&", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_8, chars:"8"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_8,
+             modifiers:{}, chars:"8"},
             nsIDOMKeyEvent.DOM_VK_8, "8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_8, shift:1, chars:"*"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_8,
+             modifiers:{shiftKey:1}, chars:"*"},
             nsIDOMKeyEvent.DOM_VK_8, "*", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_9, chars:"9"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_9,
+             modifiers:{}, chars:"9"},
             nsIDOMKeyEvent.DOM_VK_9, "9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_9, shift:1, chars:"("},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_9,
+             modifiers:{shiftKey:1}, chars:"("},
             nsIDOMKeyEvent.DOM_VK_9, "(", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // OEM keys
-    testKey({layout:"US", keyCode:WIN_VK_OEM_MINUS, chars:"-"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_MINUS,
+             modifiers:{}, chars:"-"},
             nsIDOMKeyEvent.DOM_VK_HYPHEN_MINUS, "-", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_MINUS, shift:1, chars:"_"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_MINUS,
+             modifiers:{shiftKey:1}, chars:"_"},
             nsIDOMKeyEvent.DOM_VK_HYPHEN_MINUS, "_", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_PLUS, chars:"="},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_PLUS,
+             modifiers:{}, chars:"="},
             nsIDOMKeyEvent.DOM_VK_EQUALS, "=", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_PLUS, shift:1, chars:"+"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_PLUS,
+             modifiers:{shiftKey:1}, chars:"+"},
             nsIDOMKeyEvent.DOM_VK_EQUALS, "+", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_4, chars:"["},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_4,
+             modifiers:{}, chars:"["},
             nsIDOMKeyEvent.DOM_VK_OPEN_BRACKET, "[", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_4, shift:1, chars:"{"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_4,
+             modifiers:{shiftKey:1}, chars:"{"},
             nsIDOMKeyEvent.DOM_VK_OPEN_BRACKET, "{", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_6, chars:"]"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_6,
+             modifiers:{}, chars:"]"},
             nsIDOMKeyEvent.DOM_VK_CLOSE_BRACKET, "]", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_6, shift:1, chars:"}"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_6,
+             modifiers:{shiftKey:1}, chars:"}"},
             nsIDOMKeyEvent.DOM_VK_CLOSE_BRACKET, "}", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_1, chars:";"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_1,
+             modifiers:{}, chars:";"},
             nsIDOMKeyEvent.DOM_VK_SEMICOLON, ";", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_1, shift:1, chars:":"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_1,
+             modifiers:{shiftKey:1}, chars:":"},
             nsIDOMKeyEvent.DOM_VK_SEMICOLON, ":", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_7, chars:"'"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_7,
+             modifiers:{}, chars:"'"},
             nsIDOMKeyEvent.DOM_VK_QUOTE, "'", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_7, shift:1, chars:"\""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_7,
+             modifiers:{shiftKey:1}, chars:"\""},
             nsIDOMKeyEvent.DOM_VK_QUOTE, "\"", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_5, chars:"\\"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_5,
+             modifiers:{}, chars:"\\"},
             nsIDOMKeyEvent.DOM_VK_BACK_SLASH, "\\", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_5, shift:1, chars:"|"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_5,
+             modifiers:{shiftKey:1}, chars:"|"},
             nsIDOMKeyEvent.DOM_VK_BACK_SLASH, "|", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_COMMA, chars:","},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_COMMA,
+             modifiers:{}, chars:","},
             nsIDOMKeyEvent.DOM_VK_COMMA, ",", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_COMMA, shift:1, chars:"<"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_COMMA,
+             modifiers:{shiftKey:1}, chars:"<"},
             nsIDOMKeyEvent.DOM_VK_COMMA, "<", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_PERIOD, chars:"."},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_PERIOD,
+             modifiers:{}, chars:"."},
             nsIDOMKeyEvent.DOM_VK_PERIOD, ".", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_PERIOD, shift:1, chars:">"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_PERIOD,
+             modifiers:{shiftKey:1}, chars:">"},
             nsIDOMKeyEvent.DOM_VK_PERIOD, ">", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_2, chars:"/"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_2,
+             modifiers:{}, chars:"/"},
             nsIDOMKeyEvent.DOM_VK_SLASH, "/", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_2, shift:1, chars:"?"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_2,
+             modifiers:{shiftKey:1}, chars:"?"},
             nsIDOMKeyEvent.DOM_VK_SLASH, "?", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_3, chars:"`"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_3,
+             modifiers:{}, chars:"`"},
             nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "`", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_3, shift:1, chars:"~"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_3,
+             modifiers:{shiftKey:1}, chars:"~"},
             nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "~", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Numpad
-    testKey({layout:"US", keyCode:WIN_VK_NUMPAD0, numLock:1, chars:"0"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_NUMPAD0,
+             modifiers:{numLockKey:1}, chars:"0"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD0, "0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_NUMPAD1, numLock:1, chars:"1"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_NUMPAD1,
+             modifiers:{numLockKey:1}, chars:"1"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD1, "1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_NUMPAD2, numLock:1, chars:"2"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_NUMPAD2,
+             modifiers:{numLockKey:1}, chars:"2"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD2, "2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_NUMPAD3, numLock:1, chars:"3"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_NUMPAD3,
+             modifiers:{numLockKey:1}, chars:"3"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD3, "3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_NUMPAD4, numLock:1, chars:"4"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_NUMPAD4,
+             modifiers:{numLockKey:1}, chars:"4"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD4, "4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_NUMPAD5, numLock:1, chars:"5"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_NUMPAD5,
+             modifiers:{numLockKey:1}, chars:"5"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD5, "5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_NUMPAD6, numLock:1, chars:"6"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_NUMPAD6,
+             modifiers:{numLockKey:1}, chars:"6"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD6, "6", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_NUMPAD7, numLock:1, chars:"7"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_NUMPAD7,
+             modifiers:{numLockKey:1}, chars:"7"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD7, "7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_NUMPAD8, numLock:1, chars:"8"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_NUMPAD8,
+             modifiers:{numLockKey:1}, chars:"8"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD8, "8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_NUMPAD9, numLock:1, chars:"9"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_NUMPAD9,
+             modifiers:{numLockKey:1}, chars:"9"},
             nsIDOMKeyEvent.DOM_VK_NUMPAD9, "9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
 
-    testKey({layout:"US", keyCode:WIN_VK_MULTIPLY, numLock:1, chars:"*"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_MULTIPLY,
+             modifiers:{numLockKey:1}, chars:"*"},
             nsIDOMKeyEvent.DOM_VK_MULTIPLY, "*", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_MULTIPLY, numLock:1, shift:1, chars:"*"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_MULTIPLY,
+             modifiers:{numLockKey:1, shiftKey:1}, chars:"*"},
             nsIDOMKeyEvent.DOM_VK_MULTIPLY, "*", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_ADD, numLock:1, chars:"+"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_ADD,
+             modifiers:{numLockKey:1}, chars:"+"},
             nsIDOMKeyEvent.DOM_VK_ADD, "+", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_ADD, numLock:1, shift:1, chars:"+"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_ADD,
+             modifiers:{numLockKey:1, shiftKey:1}, chars:"+"},
             nsIDOMKeyEvent.DOM_VK_ADD, "+", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
     // VK_SEPARATOR is keycode for NEC's PC-98 series whose keyboard layout was
     // different from current PC's keyboard layout and it cannot connect to
     // current PC.  Note that even if we synthesize WM_KEYDOWN with
     // VK_SEPARATOR, it doesn't work on Win7.
-    //testKey({layout:"US", keyCode:WIN_VK_SEPARATOR, numLock:1, chars:""},
+    //testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_SEPARATOR,
+    //         modifiers:{numLockKey:1}, chars:""},
     //        nsIDOMKeyEvent.DOM_VK_SEPARATOR, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    //testKey({layout:"US", keyCode:WIN_VK_SEPARATOR, numLock:1, shift:1, chars:""},
+    //testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_SEPARATOR,
+    //         modifiers:{numLockKey:1, shiftKey:1}, chars:""},
     //        nsIDOMKeyEvent.DOM_VK_SEPARATOR, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_SUBTRACT, numLock:1, chars:"-"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_SUBTRACT,
+             modifiers:{numLockKey:1}, chars:"-"},
             nsIDOMKeyEvent.DOM_VK_SUBTRACT, "-", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_SUBTRACT, numLock:1, shift:1, chars:"-"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_SUBTRACT,
+             modifiers:{numLockKey:1, shiftKey:1}, chars:"-"},
             nsIDOMKeyEvent.DOM_VK_SUBTRACT, "-", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_DECIMAL, numLock:1, chars:"."},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_DECIMAL,
+             modifiers:{numLockKey:1}, chars:"."},
             nsIDOMKeyEvent.DOM_VK_DECIMAL, ".", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_DECIMAL, numLock:1, shift:1, chars:"."},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_DECIMAL,
+             modifiers:{numLockKey:1, shiftKey:1}, chars:"."},
             nsIDOMKeyEvent.DOM_VK_DECIMAL, ".", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_DIVIDE, numLock:1, chars:"/"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_DIVIDE,
+             modifiers:{numLockKey:1}, chars:"/"},
             nsIDOMKeyEvent.DOM_VK_DIVIDE, "/", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_DIVIDE, numLock:1, shift:1, chars:"/"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_DIVIDE,
+             modifiers:{numLockKey:1, shiftKey:1}, chars:"/"},
             nsIDOMKeyEvent.DOM_VK_DIVIDE, "/", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
 
     // Numpad without NumLock
-    testKey({layout:"US", keyCode:WIN_VK_PRIOR, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_PRIOR,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_PAGE_UP, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_NEXT, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_NEXT,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_PAGE_DOWN, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_END, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_END,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_END, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_HOME, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_HOME,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_HOME, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_LEFT, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_LEFT,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_LEFT, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_UP, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_UP,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_UP, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_RIGHT, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_RIGHT,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_RIGHT, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_DOWN, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_DOWN,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_DOWN, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_INSERT, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_INSERT,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_INSERT, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_DELETE, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_DELETE,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_DELETE, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"US", keyCode:WIN_VK_CLEAR, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_CLEAR,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_CLEAR, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
 
     // Even if widget receives unknown keycode, it should dispatch key events
     // whose keycode is 0 rather than native keycode.
-    testKey({layout:"US", keyCode:0x3A, numLock:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:0x3A,
+             modifiers:{numLockKey:1}, chars:""},
             0, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // French
     // Numeric
-    testKey({layout:"French", keyCode:WIN_VK_0, chars:"\u00E0"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_0,
+             modifiers:{}, chars:"\u00E0"},
             nsIDOMKeyEvent.DOM_VK_0, "\u00E0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_0, shift:1, chars:"0"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_0,
+             modifiers:{shiftKey:1}, chars:"0"},
             nsIDOMKeyEvent.DOM_VK_0, "0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_1, chars:"&"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_1,
+             modifiers:{}, chars:"&"},
             nsIDOMKeyEvent.DOM_VK_1, "&", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_1, shift:1, chars:"1"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_1,
+             modifiers:{shiftKey:1}, chars:"1"},
             nsIDOMKeyEvent.DOM_VK_1, "1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_2, chars:"\u00E9"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_2,
+             modifiers:{}, chars:"\u00E9"},
             nsIDOMKeyEvent.DOM_VK_2, "\u00E9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_2, shift:1, chars:"2"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_2,
+             modifiers:{shiftKey:1}, chars:"2"},
             nsIDOMKeyEvent.DOM_VK_2, "2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_3, chars:"\""},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_3,
+             modifiers:{}, chars:"\""},
             nsIDOMKeyEvent.DOM_VK_3, "\"", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_3, shift:1, chars:"3"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_3,
+             modifiers:{shiftKey:1}, chars:"3"},
             nsIDOMKeyEvent.DOM_VK_3, "3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_4, chars:"'"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_4,
+             modifiers:{}, chars:"'"},
             nsIDOMKeyEvent.DOM_VK_4, "'", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_4, shift:1, chars:"4"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_4,
+             modifiers:{shiftKey:1}, chars:"4"},
             nsIDOMKeyEvent.DOM_VK_4, "4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_5, chars:"("},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_5,
+             modifiers:{}, chars:"("},
             nsIDOMKeyEvent.DOM_VK_5, "(", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_5, shift:1, chars:"5"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_5,
+             modifiers:{shiftKey:1}, chars:"5"},
             nsIDOMKeyEvent.DOM_VK_5, "5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_6, chars:"-"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_6,
+             modifiers:{}, chars:"-"},
             nsIDOMKeyEvent.DOM_VK_6, "-", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_6, shift:1, chars:"6"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_6,
+             modifiers:{shiftKey:1}, chars:"6"},
             nsIDOMKeyEvent.DOM_VK_6, "6", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_7, chars:"\u00E8"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_7,
+             modifiers:{}, chars:"\u00E8"},
             nsIDOMKeyEvent.DOM_VK_7, "\u00E8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_7, shift:1, chars:"7"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_7,
+             modifiers:{shiftKey:1}, chars:"7"},
             nsIDOMKeyEvent.DOM_VK_7, "7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_8, chars:"_"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_8,
+             modifiers:{}, chars:"_"},
             nsIDOMKeyEvent.DOM_VK_8, "_", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_8, shift:1, chars:"8"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_8,
+             modifiers:{shiftKey:1}, chars:"8"},
             nsIDOMKeyEvent.DOM_VK_8, "8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_9, chars:"\u00E7"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_9,
+             modifiers:{}, chars:"\u00E7"},
             nsIDOMKeyEvent.DOM_VK_9, "\u00E7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_9, shift:1, chars:"9"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_9,
+             modifiers:{shiftKey:1}, chars:"9"},
             nsIDOMKeyEvent.DOM_VK_9, "9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Numeric with ShiftLock
-    testKey({layout:"French", keyCode:WIN_VK_0, capsLock:1, chars:"0"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_0,
+             modifiers:{capsLockKey:1}, chars:"0"},
             nsIDOMKeyEvent.DOM_VK_0, "0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_0, capsLock:1, shift:1, chars:"\u00E0"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_0,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:"\u00E0"},
             nsIDOMKeyEvent.DOM_VK_0, "\u00E0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_1, capsLock:1, chars:"1"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_1,
+             modifiers:{capsLockKey:1}, chars:"1"},
             nsIDOMKeyEvent.DOM_VK_1, "1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_1, capsLock:1, shift:1, chars:"&"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_1,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:"&"},
             nsIDOMKeyEvent.DOM_VK_1, "&", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_2, capsLock:1, chars:"2"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_2,
+             modifiers:{capsLockKey:1}, chars:"2"},
             nsIDOMKeyEvent.DOM_VK_2, "2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_2, capsLock:1, shift:1, chars:"\u00E9"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_2,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:"\u00E9"},
             nsIDOMKeyEvent.DOM_VK_2, "\u00E9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_3, capsLock:1, chars:"3"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_3,
+             modifiers:{capsLockKey:1}, chars:"3"},
             nsIDOMKeyEvent.DOM_VK_3, "3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_3, capsLock:1, shift:1, chars:"\""},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_3,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:"\""},
             nsIDOMKeyEvent.DOM_VK_3, "\"", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_4, capsLock:1, chars:"4"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_4,
+             modifiers:{capsLockKey:1}, chars:"4"},
             nsIDOMKeyEvent.DOM_VK_4, "4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_4, capsLock:1, shift:1, chars:"'"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_4,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:"'"},
             nsIDOMKeyEvent.DOM_VK_4, "'", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_5, capsLock:1, chars:"5"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_5,
+             modifiers:{capsLockKey:1}, chars:"5"},
             nsIDOMKeyEvent.DOM_VK_5, "5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_5, capsLock:1, shift:1, chars:"("},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_5,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:"("},
             nsIDOMKeyEvent.DOM_VK_5, "(", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_6, capsLock:1, chars:"6"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_6,
+             modifiers:{capsLockKey:1}, chars:"6"},
             nsIDOMKeyEvent.DOM_VK_6, "6", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_6, capsLock:1, shift:1, chars:"-"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_6,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:"-"},
             nsIDOMKeyEvent.DOM_VK_6, "-", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_7, capsLock:1, chars:"7"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_7,
+             modifiers:{capsLockKey:1}, chars:"7"},
             nsIDOMKeyEvent.DOM_VK_7, "7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_7, capsLock:1, shift:1, chars:"\u00E8"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_7,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:"\u00E8"},
             nsIDOMKeyEvent.DOM_VK_7, "\u00E8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_8, capsLock:1, chars:"8"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_8,
+             modifiers:{capsLockKey:1}, chars:"8"},
             nsIDOMKeyEvent.DOM_VK_8, "8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_8, capsLock:1, shift:1, chars:"_"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_8,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:"_"},
             nsIDOMKeyEvent.DOM_VK_8, "_", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_9, capsLock:1, chars:"9"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_9,
+             modifiers:{capsLockKey:1}, chars:"9"},
             nsIDOMKeyEvent.DOM_VK_9, "9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_9, capsLock:1, shift:1, chars:"\u00E7"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_9,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:"\u00E7"},
             nsIDOMKeyEvent.DOM_VK_9, "\u00E7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // OEM keys
-    testKey({layout:"French", keyCode:WIN_VK_OEM_7, chars:"\u00B2"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_7,
+             modifiers:{}, chars:"\u00B2"},
             0, "\u00B2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_7, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_7,
+             modifiers:{shiftKey:1}, chars:""},
             0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_4, chars:")"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_4,
+             modifiers:{}, chars:")"},
             nsIDOMKeyEvent.DOM_VK_CLOSE_PAREN, ")", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_4, shift:1, chars:"\u00B0"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_4,
+             modifiers:{shiftKey:1}, chars:"\u00B0"},
             nsIDOMKeyEvent.DOM_VK_CLOSE_PAREN, "\u00B0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_PLUS, chars:"="},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_PLUS,
+             modifiers:{}, chars:"="},
             nsIDOMKeyEvent.DOM_VK_EQUALS, "=", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_PLUS, shift:1, chars:"+"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_PLUS,
+             modifiers:{shiftKey:1}, chars:"+"},
             nsIDOMKeyEvent.DOM_VK_EQUALS, "+", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    //testKey({layout:"French", keyCode:WIN_VK_OEM_6, chars:""},
+    //testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6,
+    //         modifiers:{}, chars:""},
     //        nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // Dead-key
-    //testKey({layout:"French", keyCode:WIN_VK_OEM_6, shift:1, chars:""},
+    //testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6,
+    //         modifiers:{shiftKey:1}, chars:""},
     //        nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // Dead-key
-    testKey({layout:"French", keyCode:WIN_VK_OEM_1, chars:"$"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_1,
+             modifiers:{}, chars:"$"},
             nsIDOMKeyEvent.DOM_VK_DOLLAR, "$", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_1, shift:1, chars:"\u00A3"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_1,
+             modifiers:{shiftKey:1}, chars:"\u00A3"},
             nsIDOMKeyEvent.DOM_VK_DOLLAR, "\u00A3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_3, chars:"\u00F9"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_3,
+             modifiers:{}, chars:"\u00F9"},
             nsIDOMKeyEvent.DOM_VK_PERCENT, "\u00F9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_3, shift:1, chars:"%"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_3,
+             modifiers:{shiftKey:1}, chars:"%"},
             nsIDOMKeyEvent.DOM_VK_PERCENT, "%", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_5, chars:"*"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_5,
+             modifiers:{}, chars:"*"},
             nsIDOMKeyEvent.DOM_VK_ASTERISK, "*", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_5, shift:1, chars:"\u00B5"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_5,
+             modifiers:{shiftKey:1}, chars:"\u00B5"},
             nsIDOMKeyEvent.DOM_VK_ASTERISK, "\u00B5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_102, chars:"<"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_102,
+             modifiers:{}, chars:"<"},
             nsIDOMKeyEvent.DOM_VK_LESS_THAN, "<", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_102, shift:1, chars:">"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_102,
+             modifiers:{shiftKey:1}, chars:">"},
             nsIDOMKeyEvent.DOM_VK_LESS_THAN, ">", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_COMMA, chars:","},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_COMMA,
+             modifiers:{}, chars:","},
             nsIDOMKeyEvent.DOM_VK_COMMA, ",", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_COMMA, shift:1, chars:"?"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_COMMA,
+             modifiers:{shiftKey:1}, chars:"?"},
             nsIDOMKeyEvent.DOM_VK_COMMA, "?", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_PERIOD, chars:";"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_PERIOD,
+             modifiers:{}, chars:";"},
             nsIDOMKeyEvent.DOM_VK_SEMICOLON, ";", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_PERIOD, shift:1, chars:"."},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_PERIOD,
+             modifiers:{shiftKey:1}, chars:"."},
             nsIDOMKeyEvent.DOM_VK_SEMICOLON, ".", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_2, chars:":"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_2,
+             modifiers:{}, chars:":"},
             nsIDOMKeyEvent.DOM_VK_COLON, ":", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_2, shift:1, chars:"/"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_2,
+             modifiers:{shiftKey:1}, chars:"/"},
             nsIDOMKeyEvent.DOM_VK_COLON, "/", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_8, chars:"!"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_8,
+             modifiers:{}, chars:"!"},
             nsIDOMKeyEvent.DOM_VK_EXCLAMATION, "!", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_8, shift:1, chars:"\u00A7"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_8,
+             modifiers:{shiftKey:1}, chars:"\u00A7"},
             nsIDOMKeyEvent.DOM_VK_EXCLAMATION, "\u00A7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // OEM keys with ShiftLock
-    testKey({layout:"French", keyCode:WIN_VK_OEM_7, capsLock:1, chars:"\u00B2"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_7,
+             modifiers:{capsLockKey:1}, chars:"\u00B2"},
             0, "\u00B2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_7, capsLock:1, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_7,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:""},
             0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_4, capsLock:1, chars:"\u00B0"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_4,
+             modifiers:{capsLockKey:1}, chars:"\u00B0"},
             nsIDOMKeyEvent.DOM_VK_CLOSE_PAREN, "\u00B0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_4, capsLock:1, shift:1, chars:")"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_4,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:")"},
             nsIDOMKeyEvent.DOM_VK_CLOSE_PAREN, ")", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_PLUS, capsLock:1, chars:"+"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_PLUS,
+             modifiers:{capsLockKey:1}, chars:"+"},
             nsIDOMKeyEvent.DOM_VK_EQUALS, "+", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_PLUS, capsLock:1, shift:1, chars:"="},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_PLUS,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:"="},
             nsIDOMKeyEvent.DOM_VK_EQUALS, "=", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    //testKey({layout:"French", keyCode:WIN_VK_OEM_6, capsLock:1, chars:""},
+    //testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6,
+    //         modifiers:{capsLockKey:1}, chars:""},
     //        0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // Dead-key
-    //testKey({layout:"French", keyCode:WIN_VK_OEM_6, capsLock:1, shift:1, chars:""},
+    //testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6,
+    //         modifiers:{capsLockKey:1, shiftKey:1}, chars:""},
     //        0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // Dead-key
-    testKey({layout:"French", keyCode:WIN_VK_OEM_1, capsLock:1, chars:"\u00A3"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_1,
+             modifiers:{capsLockKey:1}, chars:"\u00A3"},
             nsIDOMKeyEvent.DOM_VK_DOLLAR, "\u00A3", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_1, capsLock:1, shift:1, chars:"$"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_1,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:"$"},
             nsIDOMKeyEvent.DOM_VK_DOLLAR, "$", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_3, capsLock:1, chars:"%"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_3,
+             modifiers:{capsLockKey:1}, chars:"%"},
             nsIDOMKeyEvent.DOM_VK_PERCENT, "%", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_3, capsLock:1, shift:1, chars:"\u00F9"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_3,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:"\u00F9"},
             nsIDOMKeyEvent.DOM_VK_PERCENT, "\u00F9", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_5, capsLock:1, chars:"\u00B5"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_5,
+             modifiers:{capsLockKey:1}, chars:"\u00B5"},
             nsIDOMKeyEvent.DOM_VK_ASTERISK, "\u00B5", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_5, capsLock:1, shift:1, chars:"*"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_5,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:"*"},
             nsIDOMKeyEvent.DOM_VK_ASTERISK, "*", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_102, capsLock:1, chars:"<"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_102,
+             modifiers:{capsLockKey:1}, chars:"<"},
             nsIDOMKeyEvent.DOM_VK_LESS_THAN, "<", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_102, capsLock:1, shift:1, chars:">"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_102,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:">"},
             nsIDOMKeyEvent.DOM_VK_LESS_THAN, ">", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_COMMA, capsLock:1, chars:"?"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_COMMA,
+             modifiers:{capsLockKey:1}, chars:"?"},
             nsIDOMKeyEvent.DOM_VK_COMMA, "?", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_COMMA, capsLock:1, shift:1, chars:","},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_COMMA,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:","},
             nsIDOMKeyEvent.DOM_VK_COMMA, ",", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_PERIOD, capsLock:1, chars:"."},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_PERIOD,
+             modifiers:{capsLockKey:1}, chars:"."},
             nsIDOMKeyEvent.DOM_VK_SEMICOLON, ".", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_PERIOD, capsLock:1, shift:1, chars:";"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_PERIOD,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:";"},
             nsIDOMKeyEvent.DOM_VK_SEMICOLON, ";", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_2, capsLock:1, chars:"/"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_2,
+             modifiers:{capsLockKey:1}, chars:"/"},
             nsIDOMKeyEvent.DOM_VK_COLON, "/", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_2, capsLock:1, shift:1, chars:":"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_2,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:":"},
             nsIDOMKeyEvent.DOM_VK_COLON, ":", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_8, capsLock:1, chars:"\u00A7"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_8,
+             modifiers:{capsLockKey:1}, chars:"\u00A7"},
             nsIDOMKeyEvent.DOM_VK_EXCLAMATION, "\u00A7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_8, capsLock:1, shift:1, chars:"!"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_8,
+             modifiers:{capsLockKey:1, shiftKey:1}, chars:"!"},
             nsIDOMKeyEvent.DOM_VK_EXCLAMATION, "!", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // AltGr
-    testKey({layout:"French", keyCode:WIN_VK_0, altGr:1, chars:"@"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_0,
+             modifiers:{altGrKey:1}, chars:"@"},
             nsIDOMKeyEvent.DOM_VK_0, "@", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_1, altGr:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_1,
+             modifiers:{altGrKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_1, "&", SHOULD_DELIVER_ALL_BUT_NOT_CAUSE_INPUT, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    //testKey({layout:"French", keyCode:WIN_VK_2, altGr:1, chars:""},
+    //testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_2,
+    //         modifiers:{altGrKey:1}, chars:""},
     //        nsIDOMKeyEvent.DOM_VK_2, "2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // Dead-key
-    testKey({layout:"French", keyCode:WIN_VK_3, altGr:1, chars:"#"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_3,
+             modifiers:{altGrKey:1}, chars:"#"},
             nsIDOMKeyEvent.DOM_VK_3, "#", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_4, altGr:1, chars:"{"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_4,
+             modifiers:{altGrKey:1}, chars:"{"},
             nsIDOMKeyEvent.DOM_VK_4, "{", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_5, altGr:1, chars:"["},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_5,
+             modifiers:{altGrKey:1}, chars:"["},
             nsIDOMKeyEvent.DOM_VK_5, "[", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_6, altGr:1, chars:"|"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_6,
+             modifiers:{altGrKey:1}, chars:"|"},
             nsIDOMKeyEvent.DOM_VK_6, "|", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    //testKey({layout:"French", keyCode:WIN_VK_7, altGr:1, chars:""},
+    //testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_7,
+    //         modifiers:{altGrKey:1}, chars:""},
     //        nsIDOMKeyEvent.DOM_VK_7, "", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); // Dead-key
-    testKey({layout:"French", keyCode:WIN_VK_8, altGr:1, chars:"\\"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_8,
+             modifiers:{altGrKey:1}, chars:"\\"},
             nsIDOMKeyEvent.DOM_VK_8, "\\", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_9, altGr:1, chars:"^"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_9,
+             modifiers:{altGrKey:1}, chars:"^"},
             nsIDOMKeyEvent.DOM_VK_9, "^", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_4, altGr:1, chars:"]"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_4,
+             modifiers:{altGrKey:1}, chars:"]"},
             nsIDOMKeyEvent.DOM_VK_CLOSE_PAREN, "]", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_PLUS, altGr:1, chars:"}"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_PLUS,
+             modifiers:{altGrKey:1}, chars:"}"},
             nsIDOMKeyEvent.DOM_VK_EQUALS, "}", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // German
-    testKey({layout:"German", keyCode:WIN_VK_OEM_2, chars:"#"},
+    testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:WIN_VK_OEM_2,
+             modifiers:{}, chars:"#"},
             nsIDOMKeyEvent.DOM_VK_HASH, "#", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"German", keyCode:WIN_VK_OEM_2, shift:1, chars:"'"},
+    testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:WIN_VK_OEM_2,
+             modifiers:{shiftKey:1}, chars:"'"},
             nsIDOMKeyEvent.DOM_VK_HASH, "'", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Norwegian
-    testKey({layout:"Norwegian", keyCode:WIN_VK_OEM_5, chars:"|"},
+    testKey({layout:KEYBOARD_LAYOUT_NORWEGIAN, keyCode:WIN_VK_OEM_5,
+             modifiers:{}, chars:"|"},
             nsIDOMKeyEvent.DOM_VK_PIPE, "|", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Norwegian", keyCode:WIN_VK_OEM_5, shift:1, chars:"\u00A7"},
+    testKey({layout:KEYBOARD_LAYOUT_NORWEGIAN, keyCode:WIN_VK_OEM_5,
+             modifiers:{shiftKey:1}, chars:"\u00A7"},
             nsIDOMKeyEvent.DOM_VK_PIPE, "\u00A7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
     // Brazilian ABNT
-    testKey({layout:"BrazilianABNT", keyCode:WIN_VK_ABNT_C1, chars:"/"},
+    testKey({layout:KEYBOARD_LAYOUT_BRAZILIAN_ABNT, keyCode:WIN_VK_ABNT_C1,
+             modifiers:{}, chars:"/"},
             nsIDOMKeyEvent.DOM_VK_SLASH, "/", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"BrazilianABNT", keyCode:WIN_VK_ABNT_C1, shift:1, chars:"?"},
+    testKey({layout:KEYBOARD_LAYOUT_BRAZILIAN_ABNT, keyCode:WIN_VK_ABNT_C1,
+             modifiers:{shiftKey:1}, chars:"?"},
             nsIDOMKeyEvent.DOM_VK_SLASH, "?", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"BrazilianABNT", keyCode:WIN_VK_ABNT_C2, numLock:1, chars:"."},
+    testKey({layout:KEYBOARD_LAYOUT_BRAZILIAN_ABNT, keyCode:WIN_VK_ABNT_C2,
+             modifiers:{numLockKey:1}, chars:"."},
             nsIDOMKeyEvent.DOM_VK_SEPARATOR, ".", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"BrazilianABNT", keyCode:WIN_VK_DECIMAL, numLock:1, chars:","},
+    testKey({layout:KEYBOARD_LAYOUT_BRAZILIAN_ABNT, keyCode:WIN_VK_DECIMAL,
+             modifiers:{numLockKey:1}, chars:","},
             nsIDOMKeyEvent.DOM_VK_DECIMAL, ",", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
 
     // Mac JIS keyboard
     // The separator key on JIS keyboard for Mac doesn't cause any character even with Japanese keyboard layout.
-    testKey({layout:"Japanese", keyCode:WIN_VK_ABNT_C2, numLock:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_JAPANESE, keyCode:WIN_VK_ABNT_C2,
+             modifiers:{numLockKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_SEPARATOR, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
-    testKey({layout:"Japanese", keyCode:WIN_VK_DECIMAL, numLock:1, chars:"."},
+    testKey({layout:KEYBOARD_LAYOUT_JAPANESE, keyCode:WIN_VK_DECIMAL,
+             modifiers:{numLockKey:1}, chars:"."},
             nsIDOMKeyEvent.DOM_VK_DECIMAL, ".", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_NUMPAD);
 
     // Dead keys on any layouts
-    testKey({layout:"French", keyCode:WIN_VK_OEM_6, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_6, chars:"^^"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6,
+             modifiers:{}, chars:"^^"},
             nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "^^", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"French", keyCode:WIN_VK_OEM_6, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_A, chars:"\u00E2"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_A,
+             modifiers:{}, chars:"\u00E2"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00E2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"French", keyCode:WIN_VK_OEM_6, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_A, shift:1, chars:"\u00C2"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_A,
+             modifiers:{shiftKey:1}, chars:"\u00C2"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00C2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"French", keyCode:WIN_VK_OEM_6, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_Q, chars:"^q"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_Q,
+             modifiers:{}, chars:"^q"},
             nsIDOMKeyEvent.DOM_VK_Q, "^q", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"French", keyCode:WIN_VK_OEM_6, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6,
+             modifiers:{shiftKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_OEM_6, shift:1, chars:"\u00A8\u00A8"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6,
+             modifiers:{shiftKey:1}, chars:"\u00A8\u00A8"},
             nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "\u00A8\u00A8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"French", keyCode:WIN_VK_OEM_6, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6,
+             modifiers:{shiftKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_A, shift:1, chars:"\u00C4"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_A,
+             modifiers:{shiftKey:1}, chars:"\u00C4"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00C4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"French", keyCode:WIN_VK_OEM_6, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6,
+             modifiers:{shiftKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_A, chars:"\u00E4"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_A,
+             modifiers:{}, chars:"\u00E4"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00E4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"French", keyCode:WIN_VK_OEM_6, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_OEM_6,
+             modifiers:{shiftKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_CIRCUMFLEX, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"French", keyCode:WIN_VK_Q, shift:1, chars:"\u00A8Q"},
+    testKey({layout:KEYBOARD_LAYOUT_FRENCH, keyCode:WIN_VK_Q,
+             modifiers:{shiftKey:1}, chars:"\u00A8Q"},
             nsIDOMKeyEvent.DOM_VK_Q, "\u00A8Q", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_1,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_1, chars:"``"},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_1,
+             modifiers:{}, chars:"``"},
             nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "``", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_1,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Spanish", keyCode:WIN_VK_A, chars:"\u00E0"},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_A,
+             modifiers:{}, chars:"\u00E0"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00E0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_1,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Spanish", keyCode:WIN_VK_A, shift:1, chars:"\u00C0"},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_A,
+             modifiers:{shiftKey:1}, chars:"\u00C0"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00C0", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_1,
+             modifiers:{}, chars:""},
             nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Spanish", keyCode:WIN_VK_Q, chars:"`q"},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_Q,
+             modifiers:{}, chars:"`q"},
             nsIDOMKeyEvent.DOM_VK_Q, "`q", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_1, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_1,
+             modifiers:{shiftKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_1, shift:1, chars:"^^"},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_1,
+             modifiers:{shiftKey:1}, chars:"^^"},
             nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "^^", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_1, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_1,
+             modifiers:{shiftKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Spanish", keyCode:WIN_VK_A, shift:1, chars:"\u00C2"},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_A,
+             modifiers:{shiftKey:1}, chars:"\u00C2"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00C2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_1, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_1,
+             modifiers:{shiftKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Spanish", keyCode:WIN_VK_A, chars:"\u00E2"},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_A,
+             modifiers:{}, chars:"\u00E2"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00E2", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_1, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_1,
+             modifiers:{shiftKey:1}, chars:""},
             nsIDOMKeyEvent.DOM_VK_BACK_QUOTE, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Spanish", keyCode:WIN_VK_Q, shift:1, chars:"^Q"},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_Q,
+             modifiers:{shiftKey:1}, chars:"^Q"},
             nsIDOMKeyEvent.DOM_VK_Q, "^Q", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_7, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
+             modifiers:{}, chars:""},
             0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_7, chars:"\u00B4\u00B4"},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
+             modifiers:{}, chars:"\u00B4\u00B4"},
             0, "\u00B4\u00B4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_7, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
+             modifiers:{}, chars:""},
             0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Spanish", keyCode:WIN_VK_A, chars:"\u00E1"},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_A,
+             modifiers:{}, chars:"\u00E1"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00E1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_7, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
+             modifiers:{}, chars:""},
             0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Spanish", keyCode:WIN_VK_A, shift:1, chars:"\u00C1"},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_A,
+             modifiers:{shiftKey:1}, chars:"\u00C1"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00C1", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_7, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
+             modifiers:{}, chars:""},
             0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Spanish", keyCode:WIN_VK_Q, chars:"\u00B4q"},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_Q,
+             modifiers:{}, chars:"\u00B4q"},
             nsIDOMKeyEvent.DOM_VK_Q, "\u00B4q", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_7, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
+             modifiers:{shiftKey:1}, chars:""},
             0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_7, shift:1, chars:"\u00A8\u00A8"},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
+             modifiers:{shiftKey:1}, chars:"\u00A8\u00A8"},
             0, "\u00A8\u00A8", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_7, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
+             modifiers:{shiftKey:1}, chars:""},
             0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Spanish", keyCode:WIN_VK_A, shift:1, chars:"\u00C4"},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_A,
+             modifiers:{shiftKey:1}, chars:"\u00C4"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00C4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_7, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
+             modifiers:{shiftKey:1}, chars:""},
             0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Spanish", keyCode:WIN_VK_A, chars:"\u00E4"},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_A,
+             modifiers:{}, chars:"\u00E4"},
             nsIDOMKeyEvent.DOM_VK_A, "\u00E4", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
 
-    testKey({layout:"Spanish", keyCode:WIN_VK_OEM_7, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_OEM_7,
+             modifiers:{shiftKey:1}, chars:""},
             0, "", SHOULD_DELIVER_KEYDOWN_KEYUP, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
-    testKey({layout:"Spanish", keyCode:WIN_VK_Q, shift:1, chars:"\u00A8Q"},
+    testKey({layout:KEYBOARD_LAYOUT_SPANISH, keyCode:WIN_VK_Q,
+             modifiers:{shiftKey:1}, chars:"\u00A8Q"},
             nsIDOMKeyEvent.DOM_VK_Q, "\u00A8Q", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD);
   }
 
   document.removeEventListener("keydown",  onKeyEvent, false);
   document.removeEventListener("keypress", onKeyEvent, false);
   document.removeEventListener("keyup",    onKeyEvent, false);
 }
 
@@ -2148,87 +2919,113 @@ function runAccessKeyTests()
     is(activationCount, aShouldActivate ? 1 : 0, name + ", activating '" + aAccessKey + "'");
   }
 
   button.addEventListener("click", onClick, false);
   
   // These tests have to be per-plaform.
   if (IS_MAC) {
     // Basic sanity checks
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, chars:"a", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{}, chars:"a", unmodifiedChars:"a"},
             "a", false);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, ctrl:1, chars:"\u0001", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{ctrlKey:1}, chars:"\u0001", unmodifiedChars:"a"},
             "a", false);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, ctrl:1, chars:"\u0001", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{ctrlKey:1}, chars:"\u0001", unmodifiedChars:"a"},
             "A", false);
 
     // Shift-ctrl does not activate accesskeys
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, ctrl:1, shift:1, chars:"\u0001", unmodifiedChars:"A"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:"\u0001", unmodifiedChars:"A"},
             "a", false);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, ctrl:1, shift:1, chars:"\u0001", unmodifiedChars:"A"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:"\u0001", unmodifiedChars:"A"},
             "A", false);
     // Alt-ctrl activate accesskeys
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, ctrl:1, alt:1, chars:"\u0001", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{ctrlKey:1, altKey:1}, chars:"\u0001", unmodifiedChars:"a"},
             "a", true);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_A, ctrl:1, alt:1, chars:"\u0001", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_A,
+             modifiers:{ctrlKey:1, altKey:1}, chars:"\u0001", unmodifiedChars:"a"},
             "A", true);
             
     // Greek layout can activate a Latin accesskey
-    testKey({layout:"Greek", keyCode:MAC_VK_ANSI_A, ctrl:1, alt:1, chars:"\u0001", unmodifiedChars:"\u03b1"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:MAC_VK_ANSI_A,
+             modifiers:{ctrlKey:1, altKey:1}, chars:"\u0001", unmodifiedChars:"\u03b1"},
             "a", true);
-    testKey({layout:"Greek", keyCode:MAC_VK_ANSI_A, ctrl:1, alt:1, chars:"\u0001", unmodifiedChars:"\u03b1"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:MAC_VK_ANSI_A,
+             modifiers:{ctrlKey:1, altKey:1}, chars:"\u0001", unmodifiedChars:"\u03b1"},
             "A", true);
     // ... and a Greek accesskey!
-    testKey({layout:"Greek", keyCode:MAC_VK_ANSI_A, ctrl:1, alt:1, chars:"\u0001", unmodifiedChars:"\u03b1"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:MAC_VK_ANSI_A,
+             modifiers:{ctrlKey:1, altKey:1}, chars:"\u0001", unmodifiedChars:"\u03b1"},
             "\u03b1", true);
-    testKey({layout:"Greek", keyCode:MAC_VK_ANSI_A, ctrl:1, alt:1, chars:"\u0001", unmodifiedChars:"\u03b1"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:MAC_VK_ANSI_A,
+             modifiers:{ctrlKey:1, altKey:1}, chars:"\u0001", unmodifiedChars:"\u03b1"},
             "\u0391", true);
 
     // bug 359638
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Period, ctrl:1, alt:1, chars:".", unmodifiedChars:"."},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Period,
+             modifiers:{ctrlKey:1, altKey:1}, chars:".", unmodifiedChars:"."},
             ".", true);
 
     // German (KCHR/KeyTranslate case)
-    testKey({layout:"German", keyCode:MAC_VK_ANSI_A, ctrl:1, alt:1, chars:"a", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:MAC_VK_ANSI_A,
+             modifiers:{ctrlKey:1, altKey:1}, chars:"a", unmodifiedChars:"a"},
             "a", true);
-    testKey({layout:"German", keyCode:MAC_VK_ANSI_A, ctrl:1, alt:1, chars:"a", unmodifiedChars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:MAC_VK_ANSI_A,
+             modifiers:{ctrlKey:1, altKey:1}, chars:"a", unmodifiedChars:"a"},
             "A", true);
-    testKey({layout:"German", keyCode:MAC_VK_ANSI_LeftBracket, ctrl:1, alt:1, chars:"\u00fc", unmodifiedChars:"\u00fc"},
+    testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:MAC_VK_ANSI_LeftBracket,
+             modifiers:{ctrlKey:1, altKey:1}, chars:"\u00fc", unmodifiedChars:"\u00fc"},
             "\u00fc", true);
-    testKey({layout:"German", keyCode:MAC_VK_ANSI_LeftBracket, ctrl:1, alt:1, chars:"\u00fc", unmodifiedChars:"\u00fc"},
+    testKey({layout:KEYBOARD_LAYOUT_GERMAN, keyCode:MAC_VK_ANSI_LeftBracket,
+             modifiers:{ctrlKey:1, altKey:1}, chars:"\u00fc", unmodifiedChars:"\u00fc"},
             "\u00dc", true);
   }
   else if (IS_WIN) {
     // Basic sanity checks
-    testKey({layout:"US", keyCode:WIN_VK_A, chars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_A,
+             modifiers:{}, chars:"a"},
             "a", false);
-    testKey({layout:"US", keyCode:WIN_VK_A, shift:1, alt:1, chars:"A"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_A,
+             modifiers:{shiftKey:1, altKey:1}, chars:"A"},
             "a", true);
-    testKey({layout:"US", keyCode:WIN_VK_A, shift:1, alt:1, chars:"A"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_A,
+             modifiers:{shiftKey:1, altKey:1}, chars:"A"},
             "A", true);
 
     // shift-alt-ctrl does not activate accesskeys
-    testKey({layout:"US", keyCode:WIN_VK_A, ctrl:1, shift:1, alt:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_A,
+             modifiers:{ctrlKey:1, shiftKey:1, altKey:1}, chars:""},
             "a", false);
-    testKey({layout:"US", keyCode:WIN_VK_A, ctrl:1, shift:1, alt:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_A,
+             modifiers:{ctrlKey:1, shiftKey:1, altKey:1}, chars:""},
             "A", false);
 
     // Greek layout can activate a Latin accesskey
-    testKey({layout:"Greek", keyCode:WIN_VK_A, shift:1, alt:1, chars:"A"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:WIN_VK_A,
+             modifiers:{shiftKey:1, altKey:1}, chars:"A"},
             "a", true);
-    testKey({layout:"Greek", keyCode:WIN_VK_A, shift:1, alt:1, chars:"A"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:WIN_VK_A,
+             modifiers:{shiftKey:1, altKey:1}, chars:"A"},
             "A", true);
     // ... and a Greek accesskey!
-    testKey({layout:"Greek", keyCode:WIN_VK_A, shift:1, alt:1, chars:"A"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:WIN_VK_A,
+             modifiers:{shiftKey:1, altKey:1}, chars:"A"},
             "\u03b1", true);
-    testKey({layout:"Greek", keyCode:WIN_VK_A, shift:1, alt:1, chars:"A"},
+    testKey({layout:KEYBOARD_LAYOUT_GREEK, keyCode:WIN_VK_A,
+             modifiers:{shiftKey:1, altKey:1}, chars:"A"},
             "\u0391", true);
 
     // bug 359638
-    testKey({layout:"US", keyCode:WIN_VK_OEM_PERIOD, shift:1, alt:1, chars:".", unmodifiedChars:"."},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_PERIOD,
+             modifiers:{shiftKey:1, altKey:1}, chars:".", unmodifiedChars:"."},
             ".", true);
   }
   
   button.removeEventListener("click", onClick, false);
 }
 
 function runXULKeyTests()
 {
@@ -2241,101 +3038,132 @@ function runXULKeyTests()
 
     var name = eventToString(aEvent);
 
     is(elem.activeCount, aShouldActivate ? 1 : 0,
        name + " activating " + aElem);
   }
 
   if (IS_MAC) {
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Semicolon, command:1, chars:";", unmodifiedChars:";"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Semicolon,
+             modifiers:{metaKey:1}, chars:";", unmodifiedChars:";"},
             "unshiftedKey", true);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Semicolon, command:1, chars:";", unmodifiedChars:";"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Semicolon,
+             modifiers:{metaKey:1}, chars:";", unmodifiedChars:";"},
             "shiftedKey", false);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Semicolon, command:1, shift:1, chars:";", unmodifiedChars:":"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Semicolon,
+             modifiers:{metaKey:1, shiftKey:1}, chars:";", unmodifiedChars:":"},
             "shiftedKey", true);
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_Semicolon, command:1, shift:1, chars:";", unmodifiedChars:":"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_Semicolon,
+             modifiers:{metaKey:1, shiftKey:1}, chars:";", unmodifiedChars:":"},
             "unshiftedKey", false);
   }
   else if (IS_WIN) {
-    testKey({layout:"US", keyCode:WIN_VK_OEM_1, ctrl:1, chars:";"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_1,
+             modifiers:{ctrlKey:1}, chars:";"},
             "unshiftedKey", true);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_1, ctrl:1, chars:";"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_1,
+             modifiers:{ctrlKey:1}, chars:";"},
             "shiftedKey", false);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_1, ctrl:1, shift:1, chars:";"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_1,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:";"},
             "shiftedKey", true);
-    testKey({layout:"US", keyCode:WIN_VK_OEM_1, ctrl:1, shift:1, chars:";"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_OEM_1,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:";"},
             "unshiftedKey", false);
   }
 
   keyElems = ["commandOptionF"];
 
   // 429160
   if (IS_MAC) {
-    testKey({layout:"US", keyCode:MAC_VK_ANSI_F, command:1, alt:1, chars:"\u0192", unmodifiedChars:"f"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_F,
+             modifiers:{metaKey:1, altKey:1}, chars:"\u0192", unmodifiedChars:"f"},
             "commandOptionF", true);
   }
   else if (IS_WIN) {
-    testKey({layout:"US", keyCode:WIN_VK_F, ctrl:1, alt:1, chars:"\u0006"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_F,
+             modifiers:{ctrlKey:1, altKey:1}, chars:"\u0006"},
             "commandOptionF", true);
   }
   
   // 432112
   if (IS_MAC) {
-    testKey({layout:"Swedish", keyCode:MAC_VK_ANSI_Minus, command:1, shift:1, chars:"+", unmodifiedChars:"?"},
+    testKey({layout:KEYBOARD_LAYOUT_SWEDISH, keyCode:MAC_VK_ANSI_Minus,
+             modifiers:{metaKey:1, shiftKey:1}, chars:"+", unmodifiedChars:"?"},
             "question", true);
   }
   else if (IS_WIN) {
-    testKey({layout:"Swedish", keyCode:WIN_VK_OEM_PLUS, ctrl:1, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SWEDISH, keyCode:WIN_VK_OEM_PLUS,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:""},
             "question", true);
-    testKey({layout:"Swedish", keyCode:WIN_VK_OEM_PLUS, ctrl:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_SWEDISH, keyCode:WIN_VK_OEM_PLUS,
+             modifiers:{ctrlKey:1}, chars:""},
             "question", false);
   }
 
   // bug 433192
   if (IS_WIN) {
-    testKey({layout:"US", keyCode:WIN_VK_X, ctrl:1, chars:"\u0018"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_X,
+             modifiers:{ctrlKey:1}, chars:"\u0018"},
             "unshiftedX", true);
-    testKey({layout:"US", keyCode:WIN_VK_X, ctrl:1, chars:"\u0018"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_X,
+             modifiers:{ctrlKey:1}, chars:"\u0018"},
             "shiftedX", false);
-    testKey({layout:"US", keyCode:WIN_VK_X, ctrl:1, shift:1, chars:"\u0018"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_X,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:"\u0018"},
             "unshiftedX", false);
-    testKey({layout:"US", keyCode:WIN_VK_X, ctrl:1, shift:1, chars:"\u0018"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_X,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:"\u0018"},
             "shiftedX", true);
-    testKey({layout:"Arabic", keyCode:WIN_VK_X, ctrl:1, chars:"\u0018"},
+    testKey({layout:KEYBOARD_LAYOUT_ARABIC, keyCode:WIN_VK_X,
+             modifiers:{ctrlKey:1}, chars:"\u0018"},
             "unshiftedX", true);
-    testKey({layout:"Arabic", keyCode:WIN_VK_X, ctrl:1, chars:"\u0018"},
+    testKey({layout:KEYBOARD_LAYOUT_ARABIC, keyCode:WIN_VK_X,
+             modifiers:{ctrlKey:1}, chars:"\u0018"},
             "shiftedX", false);
-    testKey({layout:"Arabic", keyCode:WIN_VK_X, ctrl:1, shift:1, chars:"\u0018"},
+    testKey({layout:KEYBOARD_LAYOUT_ARABIC, keyCode:WIN_VK_X,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:"\u0018"},
             "unshiftedX", false);
-    testKey({layout:"Arabic", keyCode:WIN_VK_X, ctrl:1, shift:1, chars:"\u0018"},
+    testKey({layout:KEYBOARD_LAYOUT_ARABIC, keyCode:WIN_VK_X,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:"\u0018"},
             "shiftedX", true);
-    testKey({layout:"Hebrew", keyCode:WIN_VK_X, ctrl:1, chars:"\u0018"},
+    testKey({layout:KEYBOARD_LAYOUT_HEBREW, keyCode:WIN_VK_X,
+             modifiers:{ctrlKey:1}, chars:"\u0018"},
             "unshiftedX", true);
-    testKey({layout:"Hebrew", keyCode:WIN_VK_X, ctrl:1, chars:"\u0018"},
+    testKey({layout:KEYBOARD_LAYOUT_HEBREW, keyCode:WIN_VK_X,
+             modifiers:{ctrlKey:1}, chars:"\u0018"},
             "shiftedX", false);
-    testKey({layout:"Hebrew", keyCode:WIN_VK_X, ctrl:1, shift:1, chars:"\u0018"},
+    testKey({layout:KEYBOARD_LAYOUT_HEBREW, keyCode:WIN_VK_X,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:"\u0018"},
             "unshiftedX", false);
-    testKey({layout:"Hebrew", keyCode:WIN_VK_X, ctrl:1, shift:1, chars:"\u0018"},
+    testKey({layout:KEYBOARD_LAYOUT_HEBREW, keyCode:WIN_VK_X,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:"\u0018"},
             "shiftedX", true);
-    testKey({layout:"Japanese", keyCode:WIN_VK_OEM_PLUS, ctrl:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_JAPANESE, keyCode:WIN_VK_OEM_PLUS,
+             modifiers:{ctrlKey:1}, chars:""},
             "unshiftedPlus", false);
-    testKey({layout:"Japanese", keyCode:WIN_VK_OEM_PLUS, ctrl:1, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_JAPANESE, keyCode:WIN_VK_OEM_PLUS,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:""},
             "unshiftedPlus", true);
   }
 
   // bug 759346
   if (IS_WIN) {
-    testKey({layout:"Thai", keyCode:WIN_VK_1, ctrl:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:WIN_VK_1,
+             modifiers:{ctrlKey:1}, chars:""},
             "unshiftedPlus", false);
-    testKey({layout:"Thai", keyCode:WIN_VK_1, ctrl:1, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:WIN_VK_1,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:""},
             "unshiftedPlus", true);
-    testKey({layout:"Thai", keyCode:WIN_VK_OEM_PLUS, ctrl:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:WIN_VK_OEM_PLUS,
+             modifiers:{ctrlKey:1}, chars:""},
             "unshiftedPlus", true);
-    testKey({layout:"Thai", keyCode:WIN_VK_OEM_PLUS, ctrl:1, shift:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_THAI, keyCode:WIN_VK_OEM_PLUS,
+             modifiers:{ctrlKey:1, shiftKey:1}, chars:""},
             "unshiftedPlus", false);
   }
 }
 
 function runTextInputTests()
 {
   var textbox = document.getElementById("textbox");
 
@@ -2347,36 +3175,45 @@ function runTextInputTests()
 
     var name = eventToString(aEvent);
 
     is(textbox.value, aExpectText, name + " does not input correct text.");
   }
 
   if (IS_WIN) {
     // Basic sanity checks
-    testKey({layout:"US", keyCode:WIN_VK_A, chars:"a"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_A,
+             modifiers:{}, chars:"a"},
             "a");
-    testKey({layout:"US", keyCode:WIN_VK_A, shift:1, chars:"A"},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_A,
+             modifiers:{shiftKey:1}, chars:"A"},
             "A");
     // When Ctrl+Alt are pressed, any text should not be inputted.
-    testKey({layout:"US", keyCode:WIN_VK_A, ctrl:1, alt:1, chars:""},
+    testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:WIN_VK_A,
+             modifiers:{ctrlKey:1, altKey:1}, chars:""},
             "");
 
     // Lithuanian AltGr should be consumed at 9/0 keys pressed
-    testKey({layout:"Lithuanian", keyCode:WIN_VK_8, chars:"\u016B"},
+    testKey({layout:KEYBOARD_LAYOUT_LITHUANIAN, keyCode:WIN_VK_8,
+             modifiers:{}, chars:"\u016B"},
             "\u016B");
-    testKey({layout:"Lithuanian", keyCode:WIN_VK_9, chars:"9"},
+    testKey({layout:KEYBOARD_LAYOUT_LITHUANIAN, keyCode:WIN_VK_9,
+             modifiers:{}, chars:"9"},
             "9");
-    testKey({layout:"Lithuanian", keyCode:WIN_VK_0, chars:"0"},
+    testKey({layout:KEYBOARD_LAYOUT_LITHUANIAN, keyCode:WIN_VK_0,
+             modifiers:{}, chars:"0"},
             "0");
-    testKey({layout:"Lithuanian", keyCode:WIN_VK_8, ctrl:1, alt:1, chars:"8"},
+    testKey({layout:KEYBOARD_LAYOUT_LITHUANIAN, keyCode:WIN_VK_8,
+             modifiers:{ctrlKey:1, altKey:1}, chars:"8"},
             "8");
-    testKey({layout:"Lithuanian", keyCode:WIN_VK_9, ctrl:1, alt:1, chars:"9"},
+    testKey({layout:KEYBOARD_LAYOUT_LITHUANIAN, keyCode:WIN_VK_9,
+             modifiers:{ctrlKey:1, altKey:1}, chars:"9"},
             "9");
-    testKey({layout:"Lithuanian", keyCode:WIN_VK_0, ctrl:1, alt:1, chars:"0"},
+    testKey({layout:KEYBOARD_LAYOUT_LITHUANIAN, keyCode:WIN_VK_0,
+             modifiers:{ctrlKey:1, altKey:1}, chars:"0"},
             "0");
   }
   else
     todo(false, "runTextInputTests() checks Windows only");
 
   // XXX We need to move focus for canceling to search the autocomplete
   // result. If we don't do here, Fx will crash at end of this tests.
   document.getElementById("button").focus();
--- a/widget/tests/test_native_key_bindings_mac.html
+++ b/widget/tests/test_native_key_bindings_mac.html
@@ -91,233 +91,199 @@
       lamp catnip in viverra tail flick zzz meow etiam enim. Ac ac hiss shed
       everywhere kittens rhoncus, attack your ankles zzz iaculis kittens.
       Nullam pellentesque rip the couch iaculis rhoncus nibh, give me fish orci
       turpis purr sleep on your face quis nunc bibendum.">
 
     <script type="text/javascript;version=1.8">
       SimpleTest.waitForExplicitFinish();
 
-      let utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                         getInterface(Components.interfaces.nsIDOMWindowUtils);
-
-      let layouts = {
-        "US":              0,
-        "Greek":           1,
-        "German":          2,
-        "Swedish":         3,
-        "Dvorak-Qwerty":   4,
-        "Thai":            5
-      };
-
       let synthesizedKeys = [];
       let expectations = [];
 
       // Move to beginning of line
-      synthesizedKeys.push([layouts.US, MAC_VK_LeftArrow,
-                            {ctrl: true}, "\uf702", "\uf702"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_LeftArrow,
+                            {ctrlKey: true}, "\uf702", "\uf702"]);
       expectations.push({
         editable: [0, 0],
         textarea: [0, 0],
         input:    [0, 0]
       });
 
       // Move to end of line
-      synthesizedKeys.push([layouts.US, MAC_VK_RightArrow,
-                            {ctrl: true}, "\uf703", "\uf703"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_RightArrow,
+                            {ctrlKey: true}, "\uf703", "\uf703"]);
       expectations.push({
         editable: [73, 73],
         textarea: [72, 72],
         input:    [732, 732]
       });
 
       // Move down
-      synthesizedKeys.push([layouts.US, MAC_VK_ANSI_N,
-                            {ctrl: true}, "\u000e", "n"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_ANSI_N,
+                            {ctrlKey: true}, "\u000e", "n"]);
       expectations.push({
         editable: [140, 140],
         textarea: [145, 145],
         input:    [732, 732]
       });
 
       // Move to beginning of line
-      synthesizedKeys.push([layouts.US, MAC_VK_LeftArrow,
-                            {ctrl: true}, "\uf702", "\uf702"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_LeftArrow,
+                            {ctrlKey: true}, "\uf702", "\uf702"]);
       expectations.push({
         editable: [73, 73],
         textarea: [73, 73],
         input:    [0, 0]
       });
 
       // Move word right and modify selection
-      synthesizedKeys.push([layouts.US, MAC_VK_RightArrow,
-                            {alt: true, shift: true}, "\uf703", "\uf703"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_RightArrow,
+                            {altKey: true, shiftKey: true}, "\uf703", "\uf703"]);
       expectations.push({
         editable: [73, 84],
         textarea: [73, 90],
         input:    [0, 10]
       });
 
       // Move word right
-      synthesizedKeys.push([layouts.US, MAC_VK_RightArrow,
-                            {alt: true}, "\uf703", "\uf703"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_RightArrow,
+                            {altKey: true}, "\uf703", "\uf703"]);
       expectations.push({
         editable: [84, 84],
         textarea: [90, 90],
         input:    [10, 10]
       });
 
       // Move word right
-      synthesizedKeys.push([layouts.US, MAC_VK_RightArrow,
-                            {alt: true}, "\uf703", "\uf703"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_RightArrow,
+                            {altKey: true}, "\uf703", "\uf703"]);
       expectations.push({
         editable: [89, 89],
         textarea: [95, 95],
         input:    [17, 17]
       });
 
       // Move down and modify selection
-      synthesizedKeys.push([layouts.US, MAC_VK_DownArrow,
-                            {shift: true}, "\uf701", "\uf701"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_DownArrow,
+                            {shiftKey: true}, "\uf701", "\uf701"]);
       expectations.push({
         editable: [89, 171],
         textarea: [95, 175],
         input:    [17, 732]
       });
 
       // Move backward and modify selection
-      synthesizedKeys.push([layouts.US, MAC_VK_ANSI_B,
-                            {ctrl: true, shift: true}, "\u0002", "B"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_ANSI_B,
+                            {ctrlKey: true, shiftKey: true}, "\u0002", "B"]);
       expectations.push({
         editable: [89, 170],
         textarea: [95, 174],
         input:    [17, 731]
       });
 
       // Delete forward
-      synthesizedKeys.push([layouts.US, MAC_VK_ANSI_D,
-                            {ctrl: true}, "\u0004", "d"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_ANSI_D,
+                            {ctrlKey: true}, "\u0004", "d"]);
       expectations.push({
         editable: [89, 89],
         textarea: [95, 95],
         input:    [17, 17]
       });
 
       // Delete backward
-      synthesizedKeys.push([layouts.US, MAC_VK_ANSI_H,
-                            {ctrl: true}, "\u0008", "h"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_ANSI_H,
+                            {ctrlKey: true}, "\u0008", "h"]);
       expectations.push({
         editable: [88, 88],
         textarea: [94, 94],
         input:    [16, 16]
       });
 
       // Move backward
-      synthesizedKeys.push([layouts.US, MAC_VK_ANSI_B,
-                            {ctrl: true}, "\u0002", "b"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_ANSI_B,
+                            {ctrlKey: true}, "\u0002", "b"]);
       expectations.push({
         editable: [87, 87],
         textarea: [93, 93],
         input:    [15, 15]
       });
 
       // Move to beginning of paragraph (line for now)
-      synthesizedKeys.push([layouts.US, MAC_VK_ANSI_A,
-                            {ctrl: true}, "\u0001", "a"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_ANSI_A,
+                            {ctrlKey: true}, "\u0001", "a"]);
       expectations.push({
         editable: [73, 73],
         textarea: [73, 73],
         input:    [0, 0]
       });
 
       // Move forward
-      synthesizedKeys.push([layouts.US, MAC_VK_ANSI_F,
-                            {ctrl: true}, "\u0006", "f"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_ANSI_F,
+                            {ctrlKey: true}, "\u0006", "f"]);
       expectations.push({
         editable: [74, 74],
         textarea: [74, 74],
         input:    [1, 1]
       });
 
       // Move word right
-      synthesizedKeys.push([layouts.US, MAC_VK_RightArrow,
-                            {alt: true}, "\uf703", "\uf703"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_RightArrow,
+                            {altKey: true}, "\uf703", "\uf703"]);
       expectations.push({
         editable: [84, 84],
         textarea: [90, 90],
         input:    [10, 10]
       });
 
       // Move word right
-      synthesizedKeys.push([layouts.US, MAC_VK_RightArrow,
-                            {alt: true}, "\uf703", "\uf703"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_RightArrow,
+                            {altKey: true}, "\uf703", "\uf703"]);
       expectations.push({
         editable: [88, 88],
         textarea: [94, 94],
         input:    [17, 17]
       });
 
       // Delete to end of paragraph (line for now)
-      synthesizedKeys.push([layouts.US, MAC_VK_ANSI_K,
-                            {ctrl: true}, "\u000b", "k"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_ANSI_K,
+                            {ctrlKey: true}, "\u000b", "k"]);
       expectations.push({
         editable: [88, 88],
         textarea: [94, 94],
         input:    [17, 17]
       });
 
       // Move backward and modify selection
-      synthesizedKeys.push([layouts.US, MAC_VK_ANSI_B,
-                            {ctrl: true, shift: true}, "\u0002", "B"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_ANSI_B,
+                            {ctrlKey: true, shiftKey: true}, "\u0002", "B"]);
       expectations.push({
         editable: [88, 87],
         textarea: [93, 94],
         input:    [16, 17]
       });
 
       // Move to end of paragraph (line for now)
-      synthesizedKeys.push([layouts.US, MAC_VK_ANSI_E,
-                            {ctrl: true}, "\u0005", "e"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_ANSI_E,
+                            {ctrlKey: true}, "\u0005", "e"]);
       expectations.push({
         editable: [144, 144],
         textarea: [94, 94],
         input:    [17, 17]
       });
 
       // Move up
-      synthesizedKeys.push([layouts.US, MAC_VK_ANSI_P,
-                            {ctrl: true}, "\u0010", "p"]);
+      synthesizedKeys.push([KEYBOARD_LAYOUT_EN_US, MAC_VK_ANSI_P,
+                            {ctrlKey: true}, "\u0010", "p"]);
       expectations.push({
         editable: [73, 73],
         textarea: [21, 21],
         input:    [0, 0]
       });
 
-      function synthesizeNativeKey(aLayout, aKeyCode, aModifiers, aSystemChars,
-                                   aSystemUnmodifiedChars)
-      {
-        let modifiers = 0;
-        if (aModifiers.capsLock) modifiers |= 0x01;
-        if (aModifiers.numLock) modifiers |= 0x02;
-        if (aModifiers.shift) modifiers |= 0x0100;
-        if (aModifiers.shiftRight) modifiers |= 0x0200;
-        if (aModifiers.ctrl) modifiers |= 0x0400;
-        if (aModifiers.ctrlRight) modifiers |= 0x0800;
-        if (aModifiers.alt) modifiers |= 0x1000;
-        if (aModifiers.altRight) modifiers |= 0x2000;
-        if (aModifiers.command) modifiers |= 0x4000;
-        if (aModifiers.commandRight) modifiers |= 0x8000;
-        if (aModifiers.help) modifiers |= 0x10000;
-        if (aModifiers.function) modifiers |= 0x100000;
-        if (aModifiers.numericKeyPad) modifiers |= 0x01000000;
-
-        utils.sendNativeKeyEvent(aLayout, aKeyCode, modifiers,
-                                 aSystemChars, aSystemUnmodifiedChars);
-      }
-
       function checkWindowSelection(aElement, aSelection)
       {
         let selection = window.getSelection();
 
         is(selection.anchorOffset, aSelection[aElement.id][0],
            aElement.id + ": Incorrect anchor offset");
         is(selection.focusOffset, aSelection[aElement.id][1],
            aElement.id + ": Incorrect focus offset");
--- a/widget/tests/test_plugin_input_event.html
+++ b/widget/tests/test_plugin_input_event.html
@@ -44,29 +44,23 @@ var gUtils = window.
 function doTest() {
   gPlugin.focus();
 
   is(gUtils.IMEStatus, gUtils.IME_STATUS_PLUGIN,
      "Plugin failed to get focus");
 
   is(gPlugin.getLastKeyText(), "", "Must be empty before first key test");
 
-  gUtils.sendNativeKeyEvent(0x409 /* US */,
-                            WIN_VK_A, 0,
-                            "a", "a");
+  synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, WIN_VK_A, {}, "a", "a");
   is(gPlugin.getLastKeyText(), "a", "Invalid character was inputted");
 
-  gUtils.sendNativeKeyEvent(0x407 /* German */,
-                            WIN_VK_OEM_PLUS, 0,
-                            "+", "+");
+  synthesizeNativeKey(KEYBOARD_LAYOUT_GERMAN, WIN_VK_OEM_PLUS, {}, "+", "+");
   is(gPlugin.getLastKeyText(), "+", "Invalid character was inputted");
 
-  gUtils.sendNativeKeyEvent(0x407 /* German */,
-                            WIN_VK_OEM_PLUS, 0x1400 /* Ctrl + Alt (AltGr) */,
-                            "~", "+");
+  synthesizeNativeKey(KEYBOARD_LAYOUT_GERMAN, WIN_VK_OEM_PLUS, {altGrKey:1}, "~", "+");
   is(gPlugin.getLastKeyText(), "~", "Invalid character was inputted");
 
   SimpleTest.finish();
 }
 
 SimpleTest.waitForFocus(doTest);
 
 </script>
--- a/widget/tests/test_secure_input.html
+++ b/widget/tests/test_secure_input.html
@@ -31,18 +31,17 @@
 <div id="contenteditable" contenteditable style="min-height: 3em;"></div>
 
 <script class="testbody" type="application/javascript">
 
   SimpleTest.waitForExplicitFinish();
 
   function sendAKeyEvent()
   {
-    SpecialPowers.getDOMWindowUtils(window)
-                 .sendNativeKeyEvent(0, MAC_VK_ANSI_A, 0, "a", "a");
+    synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, MAC_VK_ANSI_A, {}, "a", "a");
   }
 
   function isFocused(aElement)
   {
     return (SpecialPowers.focusManager.focusedElement == aElement);
   }
 
   function runTest()
--- a/widget/windows/WinIMEHandler.cpp
+++ b/widget/windows/WinIMEHandler.cpp
@@ -99,16 +99,28 @@ IMEHandler::ProcessRawKeyMessage(const M
 // static
 bool
 IMEHandler::ProcessMessage(nsWindow* aWindow, UINT aMessage,
                            WPARAM& aWParam, LPARAM& aLParam,
                            MSGResult& aResult)
 {
 #ifdef NS_ENABLE_TSF
   if (IsTSFAvailable()) {
+    if (aMessage == WM_IME_SETCONTEXT) {
+      // If a windowless plugin had focus and IME was handled on it, composition
+      // window was set the position.  After that, even in TSF mode, WinXP keeps
+      // to use composition window at the position if the active IME is not
+      // aware TSF.  For avoiding this issue, we need to hide the composition
+      // window here.
+      if (aWParam) {
+        aLParam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
+      }
+      return false;
+    }
+
     if (aMessage == WM_USER_TSF_TEXTCHANGE) {
       nsTextStore::OnTextChangeMsg();
       aResult.mConsumed = true;
       return true;
     }
     return false;
   }
 #endif // #ifdef NS_ENABLE_TSF
--- a/widget/windows/nsIMM32Handler.cpp
+++ b/widget/windows/nsIMM32Handler.cpp
@@ -758,16 +758,18 @@ nsIMM32Handler::OnIMEStartCompositionOnP
                                               LPARAM lParam,
                                               MSGResult& aResult)
 {
   PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
     ("IMM32: OnIMEStartCompositionOnPlugin, hWnd=%08x, mIsComposingOnPlugin=%s\n",
      aWindow->GetWindowHandle(), mIsComposingOnPlugin ? "TRUE" : "FALSE"));
   mIsComposingOnPlugin = true;
   mComposingWindow = aWindow;
+  nsIMEContext IMEContext(aWindow->GetWindowHandle());
+  SetIMERelatedWindowsPosOnPlugin(aWindow, IMEContext);
   aResult.mConsumed =
     aWindow->DispatchPluginEvent(WM_IME_STARTCOMPOSITION, wParam, lParam,
                                  false);
   return true;
 }
 
 bool
 nsIMM32Handler::OnIMECompositionOnPlugin(nsWindow* aWindow,
@@ -790,16 +792,18 @@ nsIMM32Handler::OnIMECompositionOnPlugin
   if (IS_COMMITTING_LPARAM(lParam)) {
     mIsComposingOnPlugin = false;
     mComposingWindow = nullptr;
   }
   // Continue composition if there is still a string being composed.
   if (IS_COMPOSING_LPARAM(lParam)) {
     mIsComposingOnPlugin = true;
     mComposingWindow = aWindow;
+    nsIMEContext IMEContext(aWindow->GetWindowHandle());
+    SetIMERelatedWindowsPosOnPlugin(aWindow, IMEContext);
   }
   aResult.mConsumed =
     aWindow->DispatchPluginEvent(WM_IME_COMPOSITION, wParam, lParam, true);
   return true;
 }
 
 bool
 nsIMM32Handler::OnIMEEndCompositionOnPlugin(nsWindow* aWindow,
@@ -808,16 +812,22 @@ nsIMM32Handler::OnIMEEndCompositionOnPlu
                                             MSGResult& aResult)
 {
   PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
     ("IMM32: OnIMEEndCompositionOnPlugin, hWnd=%08x, mIsComposingOnPlugin=%s\n",
      aWindow->GetWindowHandle(), mIsComposingOnPlugin ? "TRUE" : "FALSE"));
 
   mIsComposingOnPlugin = false;
   mComposingWindow = nullptr;
+
+  if (mNativeCaretIsCreated) {
+    ::DestroyCaret();
+    mNativeCaretIsCreated = false;
+  }
+
   aResult.mConsumed =
     aWindow->DispatchPluginEvent(WM_IME_ENDCOMPOSITION, wParam, lParam,
                                  false);
   return true;
 }
 
 bool
 nsIMM32Handler::OnIMECharOnPlugin(nsWindow* aWindow,
@@ -1926,16 +1936,78 @@ nsIMM32Handler::SetIMERelatedWindowsPos(
     compForm.ptCurrentPos.y = firstSelectedCharRect.y;
     ::ImmSetCompositionWindow(aIMEContext.get(), &compForm);
   }
 
   return true;
 }
 
 void
+nsIMM32Handler::SetIMERelatedWindowsPosOnPlugin(nsWindow* aWindow,
+                                                const nsIMEContext& aIMEContext)
+{
+  WidgetQueryContentEvent editorRectEvent(true, NS_QUERY_EDITOR_RECT, aWindow);
+  aWindow->InitEvent(editorRectEvent);
+  aWindow->DispatchWindowEvent(&editorRectEvent);
+  if (!editorRectEvent.mSucceeded) {
+    PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
+      ("IMM32: SetIMERelatedWindowsPosOnPlugin, "
+       "FAILED (NS_QUERY_EDITOR_RECT)"));
+    return;
+  }
+
+  // Clip the plugin rect by the client rect of the window because composition
+  // window needs to be specified the position in the client area.
+  nsWindow* toplevelWindow = aWindow->GetTopLevelWindow(false);
+  nsIntRect pluginRectInScreen =
+    editorRectEvent.mReply.mRect + toplevelWindow->WidgetToScreenOffset();
+  nsIntRect winRectInScreen;
+  aWindow->GetClientBounds(winRectInScreen);
+  // composition window cannot be positioned on the edge of client area.
+  winRectInScreen.width--;
+  winRectInScreen.height--;
+  nsIntRect clippedPluginRect;
+  clippedPluginRect.x =
+    std::min(std::max(pluginRectInScreen.x, winRectInScreen.x),
+             winRectInScreen.XMost());
+  clippedPluginRect.y =
+    std::min(std::max(pluginRectInScreen.y, winRectInScreen.y),
+             winRectInScreen.YMost());
+  int32_t xMost = std::min(pluginRectInScreen.XMost(), winRectInScreen.XMost());
+  int32_t yMost = std::min(pluginRectInScreen.YMost(), winRectInScreen.YMost());
+  clippedPluginRect.width = std::max(0, xMost - clippedPluginRect.x);
+  clippedPluginRect.height = std::max(0, yMost - clippedPluginRect.y);
+  clippedPluginRect -= aWindow->WidgetToScreenOffset();
+
+  // Cover the plugin with native caret.  This prevents IME's window and plugin
+  // overlap.
+  if (mNativeCaretIsCreated) {
+    ::DestroyCaret();
+  }
+  mNativeCaretIsCreated =
+    ::CreateCaret(aWindow->GetWindowHandle(), nullptr,
+                  clippedPluginRect.width, clippedPluginRect.height);
+  ::SetCaretPos(clippedPluginRect.x, clippedPluginRect.y);
+
+  // Set the composition window to bottom-left of the clipped plugin.
+  // As far as we know, there is no IME for RTL language.  Therefore, this code
+  // must not need to take care of RTL environment.
+  COMPOSITIONFORM compForm;
+  compForm.dwStyle = CFS_POINT;
+  compForm.ptCurrentPos.x = clippedPluginRect.BottomLeft().x;
+  compForm.ptCurrentPos.y = clippedPluginRect.BottomLeft().y;
+  if (!::ImmSetCompositionWindow(aIMEContext.get(), &compForm)) {
+    PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
+      ("IMM32: SetIMERelatedWindowsPosOnPlugin, "
+       "FAILED to set composition window"));
+    return;
+  }
+}
+
+void
 nsIMM32Handler::ResolveIMECaretPos(nsIWidget* aReferenceWidget,
                                    nsIntRect& aCursorRect,
                                    nsIWidget* aNewOriginWidget,
                                    nsIntRect& aOutRect)
 {
   aOutRect = aCursorRect;
 
   if (aReferenceWidget == aNewOriginWidget)
--- a/widget/windows/nsIMM32Handler.h
+++ b/widget/windows/nsIMM32Handler.h
@@ -256,17 +256,19 @@ protected:
                           nsIWidget* aNewOriginWidget,
                           nsIntRect& aOutRect);
 
   bool ConvertToANSIString(const nsAFlatString& aStr,
                              UINT aCodePage,
                              nsACString& aANSIStr);
 
   bool SetIMERelatedWindowsPos(nsWindow* aWindow,
-                                 const nsIMEContext &aIMEContext);
+                               const nsIMEContext& aIMEContext);
+  void SetIMERelatedWindowsPosOnPlugin(nsWindow* aWindow,
+                                       const nsIMEContext& aIMEContext);
   bool GetCharacterRectOfSelectedTextAt(nsWindow* aWindow,
                                           uint32_t aOffset,
                                           nsIntRect &aCharRect);
   bool GetCaretRect(nsWindow* aWindow, nsIntRect &aCaretRect);
   void GetCompositionString(const nsIMEContext &aIMEContext, DWORD aIndex);
   /**
    *  Get the current target clause of composition string.
    *  If there are one or more characters whose attribute is ATTR_TARGET_*,
--- a/xpcom/base/nsAgg.h
+++ b/xpcom/base/nsAgg.h
@@ -139,17 +139,17 @@ NS_IMETHODIMP_(nsrefcnt)                
 NS_IMPL_AGGREGATED_HELPER(_class)                                           \
                                                                             \
 NS_IMETHODIMP_(nsrefcnt)                                                    \
 _class::Internal::AddRef(void)                                              \
 {                                                                           \
     _class* agg = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Downcast(this);    \
     MOZ_ASSERT(int32_t(agg->mRefCnt) >= 0, "illegal refcnt");               \
     NS_ASSERT_OWNINGTHREAD_AGGREGATE(agg, _class);                          \
-    nsrefcnt count = agg->mRefCnt.incr();                                   \
+    nsrefcnt count = agg->mRefCnt.incr(this);                               \
     NS_LOG_ADDREF(this, count, #_class, sizeof(*agg));                      \
     return count;                                                           \
 }                                                                           \
 NS_IMETHODIMP_(nsrefcnt)                                                    \
 _class::Internal::Release(void)                                             \
 {                                                                           \
     _class* agg = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Downcast(this);    \
     MOZ_ASSERT(int32_t(agg->mRefCnt) > 0, "dup release");                   \
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -66,17 +66,40 @@
 // JS objects don't always run finalizers, so the CC can't remove them from
 // the graph when they die. Fortunately, JS objects can only die during a GC,
 // so if a GC is begun during an ICC, the browser synchronously finishes off
 // the ICC, which clears the entire CC graph. If the GC and CC are scheduled
 // properly, this should be rare.
 //
 // The second problem is that objects in the graph can be changed, say by
 // being addrefed or released, or by having a field updated, after the object
-// has been added to the graph. This will be addressed in bug 937818.
+// has been added to the graph. The problem is that ICC can miss a newly
+// created reference to an object, and end up unlinking an object that is
+// actually alive.
+//
+// The basic idea of the solution, from "An on-the-fly Reference Counting
+// Garbage Collector for Java" by Levanoni and Petrank, is to notice if an
+// object has had an additional reference to it created during the collection,
+// and if so, don't collect it during the current collection. This avoids having
+// to rerun the scan as in Bacon & Rajan 2001.
+//
+// For cycle collected C++ objects, we modify AddRef to place the object in
+// the purple buffer, in addition to Release. Then, in the CC, we treat any
+// objects in the purple buffer as being alive, after graph building has
+// completed. Because they are in the purple buffer, they will be suspected
+// in the next CC, so there's no danger of leaks. This is imprecise, because
+// we will treat as live an object that has been Released but not AddRefed
+// during graph building, but that's probably rare enough that the additional
+// bookkeeping overhead is not worthwhile.
+//
+// For JS objects, the cycle collector is only looking at gray objects. If a
+// gray object is touched during ICC, it will be made black by UnmarkGray.
+// Thus, if a JS object has become black during the ICC, we treat it as live.
+// Merged JS zones have to be handled specially: we scan all zone globals.
+// If any are black, we treat the zone as being black.
 
 
 // Safety
 //
 // An XPCOM object is either scan-safe or scan-unsafe, purple-safe or
 // purple-unsafe.
 //
 // An nsISupports object is scan-safe if:
@@ -1150,17 +1173,18 @@ private:
     void CheckThreadSafety();
     void ShutdownCollect();
 
     void FixGrayBits(bool aForceGC);
     bool ShouldMergeZones(ccType aCCType);
 
     void BeginCollection(ccType aCCType, nsICycleCollectorListener *aManualListener);
     void MarkRoots(SliceBudget &aBudget);
-    void ScanRoots();
+    void ScanRoots(bool aFullySynchGraphBuild);
+    void ScanIncrementalRoots();
     void ScanWeakMaps();
 
     // returns whether anything was collected
     bool CollectWhite();
 
     void CleanupAfterCollection();
 };
 
@@ -2275,16 +2299,26 @@ nsCycleCollector::FreeSnowWhite(bool aUn
     return hadSnowWhiteObjects;
 }
 
 void
 nsCycleCollector::ForgetSkippable(bool aRemoveChildlessNodes,
                                   bool aAsyncSnowWhiteFreeing)
 {
     CheckThreadSafety();
+
+    // If we remove things from the purple buffer during graph building, we may
+    // lose track of an object that was mutated during graph building. This should
+    // only happen when somebody calls nsJSContext::CycleCollectNow explicitly
+    // requesting extra forget skippable calls, during an incremental collection.
+    // See bug 950949 for fixing this so we actually run the forgetSkippable calls.
+    if (mIncrementalPhase != IdlePhase) {
+        return;
+    }
+
     if (mJSRuntime) {
         mJSRuntime->PrepareForForgetSkippable();
     }
     MOZ_ASSERT(!mScanInProgress, "Don't forget skippable or free snow-white while scan is in progress.");
     mPurpleBuf.RemoveSkippable(this, aRemoveChildlessNodes,
                                aAsyncSnowWhiteFreeing, mForgetSkippableCB);
 }
 
@@ -2367,30 +2401,39 @@ struct ScanBlackVisitor
 private:
     uint32_t &mWhiteNodeCount;
     bool &mFailed;
 };
 
 
 struct scanVisitor
 {
-    scanVisitor(uint32_t &aWhiteNodeCount, bool &aFailed)
-        : mWhiteNodeCount(aWhiteNodeCount), mFailed(aFailed)
+    scanVisitor(uint32_t &aWhiteNodeCount, bool &aFailed, bool aWasIncremental)
+        : mWhiteNodeCount(aWhiteNodeCount), mFailed(aFailed),
+          mWasIncremental(aWasIncremental)
     {
     }
 
     bool ShouldVisitNode(PtrInfo const *pi)
     {
         return pi->mColor == grey;
     }
 
     MOZ_NEVER_INLINE void VisitNode(PtrInfo *pi)
     {
-        if (pi->mInternalRefs > pi->mRefCount && pi->mRefCount > 0)
-            Fault("traversed refs exceed refcount", pi);
+        if (pi->mInternalRefs > pi->mRefCount && pi->mRefCount > 0) {
+            // If we found more references to an object than its ref count, then
+            // the object should have already been marked as an incremental
+            // root. Note that this is imprecise, because pi could have been
+            // marked black for other reasons. Always fault if we weren't
+            // incremental, as there were no incremental roots in that case.
+            if (!mWasIncremental || pi->mColor != black) {
+                Fault("traversed refs exceed refcount", pi);
+            }
+        }
 
         if (pi->mInternalRefs == pi->mRefCount || pi->mRefCount == 0) {
             pi->mColor = white;
             ++mWhiteNodeCount;
         } else {
             GraphWalker<ScanBlackVisitor>(ScanBlackVisitor(mWhiteNodeCount, mFailed)).Walk(pi);
             MOZ_ASSERT(pi->mColor == black,
                        "Why didn't ScanBlackVisitor make pi black?");
@@ -2399,16 +2442,17 @@ struct scanVisitor
 
     void Failed() {
         mFailed = true;
     }
 
 private:
     uint32_t &mWhiteNodeCount;
     bool &mFailed;
+    bool mWasIncremental;
 };
 
 // Iterate over the WeakMaps.  If we mark anything while iterating
 // over the WeakMaps, we must iterate over all of the WeakMaps again.
 void
 nsCycleCollector::ScanWeakMaps()
 {
     bool anyChanged;
@@ -2446,38 +2490,149 @@ nsCycleCollector::ScanWeakMaps()
     } while (anyChanged);
 
     if (failed) {
         MOZ_ASSERT(false, "Ran out of memory in ScanWeakMaps");
         CC_TELEMETRY(_OOM, true);
     }
 }
 
+// Flood black from any objects in the purple buffer that are in the CC graph.
+class PurpleScanBlackVisitor
+{
+public:
+    PurpleScanBlackVisitor(GCGraph &aGraph, uint32_t &aCount, bool &aFailed)
+        : mGraph(aGraph), mCount(aCount), mFailed(aFailed)
+    {
+    }
+
+    void
+    Visit(nsPurpleBuffer &aBuffer, nsPurpleBufferEntry *aEntry)
+    {
+        MOZ_ASSERT(aEntry->mObject, "Entries with null mObject shouldn't be in the purple buffer.");
+        MOZ_ASSERT(aEntry->mRefCnt->get() != 0, "Snow-white objects shouldn't be in the purple buffer.");
+
+        void *obj = aEntry->mObject;
+        if (!aEntry->mParticipant) {
+            obj = CanonicalizeXPCOMParticipant(static_cast<nsISupports*>(obj));
+            MOZ_ASSERT(obj, "Don't add objects that don't participate in collection!");
+        }
+
+        PtrInfo *pi = mGraph.FindNode(obj);
+        if (!pi) {
+            return;
+        }
+        MOZ_ASSERT(pi->mParticipant, "No dead objects should be in the purple buffer.");
+        if (pi->mColor == black) {
+            return;
+        }
+        GraphWalker<ScanBlackVisitor>(ScanBlackVisitor(mCount, mFailed)).Walk(pi);
+    }
+
+private:
+    GCGraph &mGraph;
+    uint32_t &mCount;
+    bool &mFailed;
+};
+
+// Objects that have been stored somewhere since the start of incremental graph building must
+// be treated as live for this cycle collection, because we may not have accurate information
+// about who holds references to them.
 void
-nsCycleCollector::ScanRoots()
+nsCycleCollector::ScanIncrementalRoots()
 {
     TimeLog timeLog;
+
+    // Reference counted objects:
+    // We cleared the purple buffer at the start of the current ICC, so if a
+    // refcounted object is purple, it may have been AddRef'd during the current
+    // ICC. (It may also have only been released.) If that is the case, we cannot
+    // be sure that the set of things pointing to the object in the CC graph
+    // is accurate. Therefore, for safety, we treat any purple objects as being
+    // live during the current CC. We don't remove anything from the purple
+    // buffer here, so these objects will be suspected and freed in the next CC
+    // if they are garbage.
+    bool failed = false;
+    PurpleScanBlackVisitor purpleScanBlackVisitor(mGraph, mWhiteNodeCount, failed);
+    mPurpleBuf.VisitEntries(purpleScanBlackVisitor);
+    timeLog.Checkpoint("ScanIncrementalRoots::fix purple");
+
+    // Garbage collected objects:
+    // If a GCed object was added to the graph with a refcount of zero, and is
+    // now marked black by the GC, it was probably gray before and was exposed
+    // to active JS, so it may have been stored somewhere, so it needs to be
+    // treated as live.
+    if (mJSRuntime) {
+        nsCycleCollectionParticipant *jsParticipant = mJSRuntime->GCThingParticipant();
+        nsCycleCollectionParticipant *zoneParticipant = mJSRuntime->ZoneParticipant();
+        NodePool::Enumerator etor(mGraph.mNodes);
+
+        while (!etor.IsDone()) {
+            PtrInfo *pi = etor.GetNext();
+
+            if (pi->mRefCount != 0 || pi->mColor == black) {
+                continue;
+            }
+
+            if (pi->mParticipant == jsParticipant) {
+                if (xpc_GCThingIsGrayCCThing(pi->mPointer)) {
+                    continue;
+                }
+            } else if (pi->mParticipant == zoneParticipant) {
+                JS::Zone *zone = static_cast<JS::Zone*>(pi->mPointer);
+                if (js::ZoneGlobalsAreAllGray(zone)) {
+                    continue;
+                }
+            } else {
+                MOZ_ASSERT(false, "Non-JS thing with 0 refcount? Treating as live.");
+            }
+
+            GraphWalker<ScanBlackVisitor>(ScanBlackVisitor(mWhiteNodeCount, failed)).Walk(pi);
+        }
+
+        timeLog.Checkpoint("ScanIncrementalRoots::fix JS");
+    }
+
+    if (failed) {
+        NS_ASSERTION(false, "Ran out of memory in ScanIncrementalRoots");
+        CC_TELEMETRY(_OOM, true);
+    }
+}
+
+void
+nsCycleCollector::ScanRoots(bool aFullySynchGraphBuild)
+{
     AutoRestore<bool> ar(mScanInProgress);
     MOZ_ASSERT(!mScanInProgress);
     mScanInProgress = true;
     mWhiteNodeCount = 0;
     MOZ_ASSERT(mIncrementalPhase == ScanAndCollectWhitePhase);
 
+    if (!aFullySynchGraphBuild) {
+        ScanIncrementalRoots();
+    }
+
+    TimeLog timeLog;
+
     // On the assumption that most nodes will be black, it's
     // probably faster to use a GraphWalker than a
     // NodePool::Enumerator.
     bool failed = false;
-    GraphWalker<scanVisitor>(scanVisitor(mWhiteNodeCount, failed)).WalkFromRoots(mGraph);
+    scanVisitor sv(mWhiteNodeCount, failed, !aFullySynchGraphBuild);
+    GraphWalker<scanVisitor>(sv).WalkFromRoots(mGraph);
+    timeLog.Checkpoint("ScanRoots::WalkFromRoots");
 
     if (failed) {
         NS_ASSERTION(false, "Ran out of memory in ScanRoots");
         CC_TELEMETRY(_OOM, true);
     }
 
+    // Scanning weak maps must be done last.
     ScanWeakMaps();
+    timeLog.Checkpoint("ScanRoots::ScanWeakMaps");
 
     if (mListener) {
         mListener->BeginResults();
 
         NodePool::Enumerator etor(mGraph.mNodes);
         while (!etor.IsDone()) {
             PtrInfo *pi = etor.GetNext();
             if (!pi->mParticipant) {
@@ -2498,19 +2653,18 @@ nsCycleCollector::ScanRoots()
                 // With incremental CC, we can end up with a grey object after
                 // scanning if it is only reachable from an object that gets freed.
                 break;
             }
         }
 
         mListener->End();
         mListener = nullptr;
+        timeLog.Checkpoint("ScanRoots::listener");
     }
-
-    timeLog.Checkpoint("ScanRoots()");
 }
 
 
 ////////////////////////////////////////////////////////////////////////
 // Bacon & Rajan's |CollectWhite| routine, somewhat modified.
 ////////////////////////////////////////////////////////////////////////
 
 bool
@@ -2863,17 +3017,17 @@ nsCycleCollector::Collect(ccType aCCType
             MarkRoots(aBudget);
             break;
         case ScanAndCollectWhitePhase:
             // We do ScanRoots and CollectWhite in a single slice to ensure
             // that we won't unlink a live object if a weak reference is
             // promoted to a strong reference after ScanRoots has finished.
             // See bug 926533.
             PrintPhase("ScanRoots");
-            ScanRoots();
+            ScanRoots(startedIdle);
             PrintPhase("CollectWhite");
             collectedAny = CollectWhite();
             break;
         case CleanupPhase:
             PrintPhase("CleanupAfterCollection");
             CleanupAfterCollection();
             finished = true;
             break;
--- a/xpcom/glue/nsISupportsImpl.h
+++ b/xpcom/glue/nsISupportsImpl.h
@@ -87,20 +87,33 @@ public:
     : mRefCntAndFlags(0)
   {}
 
   nsCycleCollectingAutoRefCnt(uintptr_t aValue)
     : mRefCntAndFlags(aValue << NS_NUMBER_OF_FLAGS_IN_REFCNT)
   {
   }
 
-  MOZ_ALWAYS_INLINE uintptr_t incr()
+  MOZ_ALWAYS_INLINE uintptr_t incr(nsISupports *owner)
+  {
+    return incr(owner, nullptr);
+  }
+
+  MOZ_ALWAYS_INLINE uintptr_t incr(void *owner, nsCycleCollectionParticipant *p)
   {
     mRefCntAndFlags += NS_REFCOUNT_CHANGE;
     mRefCntAndFlags &= ~NS_IS_PURPLE;
+    // For incremental cycle collection, use the purple buffer to track objects
+    // that have been AddRef'd.
+    if (!IsInPurpleBuffer()) {
+      mRefCntAndFlags |= NS_IN_PURPLE_BUFFER;
+      // Refcount isn't zero, so Suspect won't delete anything.
+      MOZ_ASSERT(get() > 0);
+      NS_CycleCollectorSuspect3(owner, p, this, nullptr);
+    }
     return NS_REFCOUNT_VALUE(mRefCntAndFlags);
   }
 
   MOZ_ALWAYS_INLINE void stabilizeForDeletion()
   {
     // Set refcnt to 1 and mark us to be in the purple buffer.
     // This way decr won't call suspect again.
     mRefCntAndFlags = NS_REFCOUNT_CHANGE | NS_IN_PURPLE_BUFFER;
@@ -260,17 +273,19 @@ public:
 /*
  * Implementation of AddRef and Release for non-nsISupports (ie "native")
  * cycle-collected classes that use the purple buffer to avoid leaks.
  */
 
 #define NS_IMPL_CC_NATIVE_ADDREF_BODY(_class)                                 \
     MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");                      \
     NS_ASSERT_OWNINGTHREAD(_class);                                           \
-    nsrefcnt count = mRefCnt.incr();                                          \
+    nsrefcnt count =                                                          \
+      mRefCnt.incr(static_cast<void*>(this),                                  \
+                   _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
     NS_LOG_ADDREF(this, count, #_class, sizeof(*this));                       \
     return count;
 
 #define NS_IMPL_CC_NATIVE_RELEASE_BODY(_class)                                \
     MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");                          \
     NS_ASSERT_OWNINGTHREAD(_class);                                           \
     nsrefcnt count =                                                          \
       mRefCnt.decr(static_cast<void*>(this),                                  \
@@ -291,17 +306,18 @@ NS_METHOD_(nsrefcnt) _class::Release(voi
     NS_ASSERT_OWNINGTHREAD(_class);                                              \
     bool shouldDelete = false;                                                   \
     nsrefcnt count =                                                             \
       mRefCnt.decr(static_cast<void*>(this),                                     \
                    _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant(),     \
                    &shouldDelete);                                               \
     NS_LOG_RELEASE(this, count, #_class);                                        \
     if (count == 0) {                                                            \
-        mRefCnt.incr();                                                          \
+        mRefCnt.incr(static_cast<void*>(this),                                   \
+                     _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant());  \
         _last;                                                                   \
         mRefCnt.decr(static_cast<void*>(this),                                   \
                      _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant());  \
         if (shouldDelete) {                                                      \
             mRefCnt.stabilizeForDeletion();                                      \
             DeleteCycleCollectable();                                            \
         }                                                                        \
     }                                                                            \
@@ -497,17 +513,18 @@ NS_IMETHODIMP_(nsrefcnt) _class::Release
 }
 
 
 #define NS_IMPL_CYCLE_COLLECTING_ADDREF(_class)                               \
 NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void)                                 \
 {                                                                             \
   MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");                        \
   NS_ASSERT_OWNINGTHREAD(_class);                                             \
-  nsrefcnt count = mRefCnt.incr();                                            \
+  nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this);    \
+  nsrefcnt count = mRefCnt.incr(base);                                        \
   NS_LOG_ADDREF(this, count, #_class, sizeof(*this));                         \
   return count;                                                               \
 }
 
 #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, _destroy)       \
 NS_IMETHODIMP_(nsrefcnt) _class::Release(void)                                \
 {                                                                             \
   MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");                            \
@@ -532,17 +549,17 @@ NS_IMETHODIMP_(nsrefcnt) _class::Release
 {                                                                             \
   MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");                            \
   NS_ASSERT_OWNINGTHREAD(_class);                                             \
   bool shouldDelete = false;                                                  \
   nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this);    \
   nsrefcnt count = mRefCnt.decr(base, &shouldDelete);                         \
   NS_LOG_RELEASE(this, count, #_class);                                       \
   if (count == 0) {                                                           \
-      mRefCnt.incr();                                                         \
+      mRefCnt.incr(base);                                                     \
       _last;                                                                  \
       mRefCnt.decr(base);                                                     \
       if (shouldDelete) {                                                     \
           mRefCnt.stabilizeForDeletion();                                     \
           DeleteCycleCollectable();                                           \
       }                                                                       \
   }                                                                           \
   return count;                                                               \