Bug 751749 part.2 Support Win key for a modifier of shortcut key and access key r=smaug, enn
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 19 Jul 2012 10:28:16 +0900
changeset 99727 372c0dbbfb5b6b305579ee85b442683aa6046d6f
parent 99726 90f71c5e14d88a7cb054144af7924fddd9f3d7d3
child 99728 ae94d3a4497e5962de06dd58ded2b8376beb9765
push id12164
push usermasayuki@d-toybox.com
push dateThu, 19 Jul 2012 01:28:44 +0000
treeherdermozilla-inbound@205aaea8796d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, enn
bugs751749
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 751749 part.2 Support Win key for a modifier of shortcut key and access key r=smaug, enn
accessible/src/generic/Accessible.h
accessible/src/xul/XULMenuAccessible.cpp
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
content/events/src/nsEventStateManager.cpp
content/xbl/src/nsXBLPrototypeHandler.cpp
content/xbl/src/nsXBLPrototypeHandler.h
layout/xul/base/src/nsMenuBarListener.cpp
layout/xul/base/src/nsMenuFrame.cpp
modules/libpref/src/init/all.js
toolkit/content/tests/chrome/window_keys.xul
toolkit/locales/en-US/chrome/global-platform/mac/platformKeys.properties
toolkit/locales/en-US/chrome/global-platform/unix/platformKeys.properties
toolkit/locales/en-US/chrome/global-platform/win/platformKeys.properties
widget/gtk2/nsGtkKeyUtils.cpp
widget/nsGUIEvent.h
widget/windows/nsWindow.cpp
--- a/accessible/src/generic/Accessible.h
+++ b/accessible/src/generic/Accessible.h
@@ -913,16 +913,17 @@ class KeyBinding
 public:
   /**
    * Modifier mask values.
    */
   static const PRUint32 kShift = 1;
   static const PRUint32 kControl = 2;
   static const PRUint32 kAlt = 4;
   static const PRUint32 kMeta = 8;
+  static const PRUint32 kOS = 16;
 
   KeyBinding() : mKey(0), mModifierMask(0) {}
   KeyBinding(PRUint32 aKey, PRUint32 aModifierMask) :
     mKey(aKey), mModifierMask(aModifierMask) {};
 
   inline bool IsEmpty() const { return !mKey; }
   inline PRUint32 Key() const { return mKey; }
   inline PRUint32 ModifierMask() const { return mModifierMask; }
--- a/accessible/src/xul/XULMenuAccessible.cpp
+++ b/accessible/src/xul/XULMenuAccessible.cpp
@@ -179,16 +179,19 @@ XULMenuitemAccessible::AccessKey() const
           modifierKey = KeyBinding::kControl;
           break;
         case nsIDOMKeyEvent::DOM_VK_ALT:
           modifierKey = KeyBinding::kAlt;
           break;
         case nsIDOMKeyEvent::DOM_VK_META:
           modifierKey = KeyBinding::kMeta;
           break;
+        case nsIDOMKeyEvent::DOM_VK_WIN:
+          modifierKey = KeyBinding::kOS;
+          break;
       }
     }
   }
 
   return KeyBinding(accesskey[0], modifierKey);
 }
 
 KeyBinding
@@ -221,25 +224,31 @@ XULMenuitemAccessible::KeyboardShortcut(
 
   PRUint32 modifierMask = 0;
   if (modifiersStr.Find("shift") != -1)
     modifierMask |= KeyBinding::kShift;
   if (modifiersStr.Find("alt") != -1)
     modifierMask |= KeyBinding::kAlt;
   if (modifiersStr.Find("meta") != -1)
     modifierMask |= KeyBinding::kMeta;
+  if (modifiersStr.Find("os") != -1)
+    modifierMask |= KeyBinding::kOS;
   if (modifiersStr.Find("control") != -1)
     modifierMask |= KeyBinding::kControl;
   if (modifiersStr.Find("accel") != -1) {
     // Get the accelerator key value from prefs, overriding the default.
     switch (Preferences::GetInt("ui.key.accelKey", 0)) {
       case nsIDOMKeyEvent::DOM_VK_META:
         modifierMask |= KeyBinding::kMeta;
         break;
 
+      case nsIDOMKeyEvent::DOM_VK_WIN:
+        modifierMask |= KeyBinding::kOS;
+        break;
+
       case nsIDOMKeyEvent::DOM_VK_ALT:
         modifierMask |= KeyBinding::kAlt;
         break;
 
       case nsIDOMKeyEvent::DOM_VK_CONTROL:
         modifierMask |= KeyBinding::kControl;
         break;
 
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1865,16 +1865,17 @@ public:
    * nsEventStateManager::IsHandlingUserInput() stops returning true.
    * This enables us to detect long running user-generated event handlers.
    */
   static TimeDuration HandlingUserInputTimeout();
 
   static void GetShiftText(nsAString& text);
   static void GetControlText(nsAString& text);
   static void GetMetaText(nsAString& text);
+  static void GetOSText(nsAString& text);
   static void GetAltText(nsAString& text);
   static void GetModifierSeparatorText(nsAString& text);
 
   /**
    * Returns if aContent has a tabbable subdocument.
    * A sub document isn't tabbable when it's a zombie document.
    *
    * @param aElement element to test.
@@ -2169,16 +2170,17 @@ private:
   /**
    * True if there's a fragment parser activation on the stack.
    */
   static bool sFragmentParsingActive;
 
   static nsString* sShiftText;
   static nsString* sControlText;
   static nsString* sMetaText;
+  static nsString* sOSText;
   static nsString* sAltText;
   static nsString* sModifierSeparator;
 };
 
 typedef nsCharSeparatedTokenizerTemplate<nsContentUtils::IsHTMLWhitespace>
                                                     HTMLSplitOnSpacesTokenizer;
 
 #define NS_HOLD_JS_OBJECTS(obj, clazz)                                         \
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -211,16 +211,17 @@ PRUint32 nsContentUtils::sRunnersCountAt
 nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nsnull;
 
 bool nsContentUtils::sIsHandlingKeyBoardEvent = false;
 bool nsContentUtils::sAllowXULXBL_for_file = false;
 
 nsString* nsContentUtils::sShiftText = nsnull;
 nsString* nsContentUtils::sControlText = nsnull;
 nsString* nsContentUtils::sMetaText = nsnull;
+nsString* nsContentUtils::sOSText = nsnull;
 nsString* nsContentUtils::sAltText = nsnull;
 nsString* nsContentUtils::sModifierSeparator = nsnull;
 
 bool nsContentUtils::sInitialized = false;
 bool nsContentUtils::sIsFullScreenApiEnabled = false;
 bool nsContentUtils::sTrustedFullScreenOnly = true;
 bool nsContentUtils::sIsIdleObserverAPIEnabled = false;
 
@@ -431,16 +432,25 @@ void
 nsContentUtils::GetMetaText(nsAString& text)
 {
   if (!sMetaText)
     InitializeModifierStrings();
   text.Assign(*sMetaText);
 }
 
 void
+nsContentUtils::GetOSText(nsAString& text)
+{
+  if (!sOSText) {
+    InitializeModifierStrings();
+  }
+  text.Assign(*sOSText);
+}
+
+void
 nsContentUtils::GetAltText(nsAString& text)
 {
   if (!sAltText)
     InitializeModifierStrings();
   text.Assign(*sAltText);
 }
 
 void
@@ -462,30 +472,33 @@ nsContentUtils::InitializeModifierString
   if (bundleService) {
     rv = bundleService->CreateBundle( "chrome://global-platform/locale/platformKeys.properties",
                                       getter_AddRefs(bundle));
   }
   
   NS_ASSERTION(NS_SUCCEEDED(rv) && bundle, "chrome://global/locale/platformKeys.properties could not be loaded");
   nsXPIDLString shiftModifier;
   nsXPIDLString metaModifier;
+  nsXPIDLString osModifier;
   nsXPIDLString altModifier;
   nsXPIDLString controlModifier;
   nsXPIDLString modifierSeparator;
   if (bundle) {
     //macs use symbols for each modifier key, so fetch each from the bundle, which also covers i18n
     bundle->GetStringFromName(NS_LITERAL_STRING("VK_SHIFT").get(), getter_Copies(shiftModifier));
     bundle->GetStringFromName(NS_LITERAL_STRING("VK_META").get(), getter_Copies(metaModifier));
+    bundle->GetStringFromName(NS_LITERAL_STRING("VK_WIN").get(), getter_Copies(osModifier));
     bundle->GetStringFromName(NS_LITERAL_STRING("VK_ALT").get(), getter_Copies(altModifier));
     bundle->GetStringFromName(NS_LITERAL_STRING("VK_CONTROL").get(), getter_Copies(controlModifier));
     bundle->GetStringFromName(NS_LITERAL_STRING("MODIFIER_SEPARATOR").get(), getter_Copies(modifierSeparator));
   }
   //if any of these don't exist, we get  an empty string
   sShiftText = new nsString(shiftModifier);
   sMetaText = new nsString(metaModifier);
+  sOSText = new nsString(osModifier);
   sAltText = new nsString(altModifier);
   sControlText = new nsString(controlModifier);
   sModifierSeparator = new nsString(modifierSeparator);  
 }
 
 bool nsContentUtils::sImgLoaderInitialized;
 
 void
@@ -1448,16 +1461,18 @@ nsContentUtils::Shutdown()
   sBlockedScriptRunners = nsnull;
 
   delete sShiftText;
   sShiftText = nsnull;
   delete sControlText;  
   sControlText = nsnull;
   delete sMetaText;  
   sMetaText = nsnull;
+  delete sOSText;
+  sOSText = nsnull;
   delete sAltText;  
   sAltText = nsnull;
   delete sModifierSeparator;
   sModifierSeparator = nsnull;
 
   NS_IF_RELEASE(sSameOriginChecker);
   
   nsTextEditorState::ShutDown();
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -261,16 +261,17 @@ enum {
  MOUSE_SCROLL_PIXELS
 };
 
 // mask values for ui.key.chromeAccess and ui.key.contentAccess
 #define NS_MODIFIER_SHIFT    1
 #define NS_MODIFIER_CONTROL  2
 #define NS_MODIFIER_ALT      4
 #define NS_MODIFIER_META     8
+#define NS_MODIFIER_OS       16
 
 static nsIDocument *
 GetDocumentFromWindow(nsIDOMWindow *aWindow)
 {
   nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aWindow);
   nsCOMPtr<nsIDocument> doc;
 
   if (win) {
@@ -285,16 +286,17 @@ GetAccessModifierMaskFromPref(PRInt32 aI
 {
   PRInt32 accessKey = Preferences::GetInt("ui.key.generalAccessKey", -1);
   switch (accessKey) {
     case -1:                             break; // use the individual prefs
     case nsIDOMKeyEvent::DOM_VK_SHIFT:   return NS_MODIFIER_SHIFT;
     case nsIDOMKeyEvent::DOM_VK_CONTROL: return NS_MODIFIER_CONTROL;
     case nsIDOMKeyEvent::DOM_VK_ALT:     return NS_MODIFIER_ALT;
     case nsIDOMKeyEvent::DOM_VK_META:    return NS_MODIFIER_META;
+    case nsIDOMKeyEvent::DOM_VK_WIN:     return NS_MODIFIER_OS;
     default:                             return 0;
   }
 
   switch (aItemType) {
   case nsIDocShellTreeItem::typeChrome:
     return Preferences::GetInt("ui.key.chromeAccess", 0);
   case nsIDocShellTreeItem::typeContent:
     return Preferences::GetInt("ui.key.contentAccess", 0);
@@ -1162,16 +1164,18 @@ nsEventStateManager::PreHandleEvent(nsPr
       if (keyEvent->IsShift())
         modifierMask |= NS_MODIFIER_SHIFT;
       if (keyEvent->IsControl())
         modifierMask |= NS_MODIFIER_CONTROL;
       if (keyEvent->IsAlt())
         modifierMask |= NS_MODIFIER_ALT;
       if (keyEvent->IsMeta())
         modifierMask |= NS_MODIFIER_META;
+      if (keyEvent->IsOS())
+        modifierMask |= NS_MODIFIER_OS;
 
       // Prevent keyboard scrolling while an accesskey modifier is in use.
       if (modifierMask && (modifierMask == sChromeAccessModifier ||
                            modifierMask == sContentAccessModifier))
         HandleAccessKey(aPresContext, keyEvent, aStatus, nsnull,
                         eAccessKeyProcessingNormal, modifierMask);
     }
     // then fall through...
@@ -1519,16 +1523,20 @@ nsEventStateManager::GetAccessKeyLabelPr
   if (modifier & NS_MODIFIER_CONTROL) {
     nsContentUtils::GetControlText(modifierText);
     aPrefix.Append(modifierText + separator);
   }
   if (modifier & NS_MODIFIER_META) {
     nsContentUtils::GetMetaText(modifierText);
     aPrefix.Append(modifierText + separator);
   }
+  if (modifier & NS_MODIFIER_OS) {
+    nsContentUtils::GetOSText(modifierText);
+    aPrefix.Append(modifierText + separator);
+  }
   if (modifier & NS_MODIFIER_ALT) {
     nsContentUtils::GetAltText(modifierText);
     aPrefix.Append(modifierText + separator);
   }
   if (modifier & NS_MODIFIER_SHIFT) {
     nsContentUtils::GetShiftText(modifierText);
     aPrefix.Append(modifierText + separator);
   }
--- a/content/xbl/src/nsXBLPrototypeHandler.cpp
+++ b/content/xbl/src/nsXBLPrototypeHandler.cpp
@@ -56,23 +56,26 @@ PRUint32 nsXBLPrototypeHandler::gRefCnt 
 
 PRInt32 nsXBLPrototypeHandler::kMenuAccessKey = -1;
 PRInt32 nsXBLPrototypeHandler::kAccelKey = -1;
 
 const PRInt32 nsXBLPrototypeHandler::cShift = (1<<0);
 const PRInt32 nsXBLPrototypeHandler::cAlt = (1<<1);
 const PRInt32 nsXBLPrototypeHandler::cControl = (1<<2);
 const PRInt32 nsXBLPrototypeHandler::cMeta = (1<<3);
+const PRInt32 nsXBLPrototypeHandler::cOS = (1<<4);
 
-const PRInt32 nsXBLPrototypeHandler::cShiftMask = (1<<4);
-const PRInt32 nsXBLPrototypeHandler::cAltMask = (1<<5);
-const PRInt32 nsXBLPrototypeHandler::cControlMask = (1<<6);
-const PRInt32 nsXBLPrototypeHandler::cMetaMask = (1<<7);
+const PRInt32 nsXBLPrototypeHandler::cShiftMask = (1<<5);
+const PRInt32 nsXBLPrototypeHandler::cAltMask = (1<<6);
+const PRInt32 nsXBLPrototypeHandler::cControlMask = (1<<7);
+const PRInt32 nsXBLPrototypeHandler::cMetaMask = (1<<8);
+const PRInt32 nsXBLPrototypeHandler::cOSMask = (1<<9);
 
-const PRInt32 nsXBLPrototypeHandler::cAllModifiers = cShiftMask | cAltMask | cControlMask | cMetaMask;
+const PRInt32 nsXBLPrototypeHandler::cAllModifiers =
+  cShiftMask | cAltMask | cControlMask | cMetaMask | cOSMask;
 
 nsXBLPrototypeHandler::nsXBLPrototypeHandler(const PRUnichar* aEvent,
                                              const PRUnichar* aPhase,
                                              const PRUnichar* aAction,
                                              const PRUnichar* aCommand,
                                              const PRUnichar* aKeyCode,
                                              const PRUnichar* aCharCode,
                                              const PRUnichar* aModifiers,
@@ -491,16 +494,18 @@ nsXBLPrototypeHandler::DispatchXULKeyCom
 
   // Copy the modifiers from the key event.
   nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
   if (!keyEvent) {
     NS_ERROR("Trying to execute a key handler for a non-key event!");
     return NS_ERROR_FAILURE;
   }
 
+  // XXX We should use widget::Modifiers for supporting all modifiers.
+
   bool isAlt = false;
   bool isControl = false;
   bool isShift = false;
   bool isMeta = false;
   keyEvent->GetAltKey(&isAlt);
   keyEvent->GetCtrlKey(&isControl);
   keyEvent->GetShiftKey(&isShift);
   keyEvent->GetMetaKey(&isMeta);
@@ -641,21 +646,22 @@ PRInt32 nsXBLPrototypeHandler::GetMatchi
 }
 
 PRInt32 nsXBLPrototypeHandler::KeyToMask(PRInt32 key)
 {
   switch (key)
   {
     case nsIDOMKeyEvent::DOM_VK_META:
       return cMeta | cMetaMask;
-      break;
+
+    case nsIDOMKeyEvent::DOM_VK_WIN:
+      return cOS | cOSMask;
 
     case nsIDOMKeyEvent::DOM_VK_ALT:
       return cAlt | cAltMask;
-      break;
 
     case nsIDOMKeyEvent::DOM_VK_CONTROL:
     default:
       return cControl | cControlMask;
   }
   return cControl | cControlMask;  // for warning avoidance
 }
 
@@ -752,24 +758,26 @@ nsXBLPrototypeHandler::ConstructPrototyp
     char* token = nsCRT::strtok( str, ", \t", &newStr );
     while( token != NULL ) {
       if (PL_strcmp(token, "shift") == 0)
         mKeyMask |= cShift | cShiftMask;
       else if (PL_strcmp(token, "alt") == 0)
         mKeyMask |= cAlt | cAltMask;
       else if (PL_strcmp(token, "meta") == 0)
         mKeyMask |= cMeta | cMetaMask;
+      else if (PL_strcmp(token, "os") == 0)
+        mKeyMask |= cOS | cOSMask;
       else if (PL_strcmp(token, "control") == 0)
         mKeyMask |= cControl | cControlMask;
       else if (PL_strcmp(token, "accel") == 0)
         mKeyMask |= KeyToMask(kAccelKey);
       else if (PL_strcmp(token, "access") == 0)
         mKeyMask |= KeyToMask(kMenuAccessKey);
       else if (PL_strcmp(token, "any") == 0)
-        mKeyMask &= ~(mKeyMask << 4);
+        mKeyMask &= ~(mKeyMask << 5);
     
       token = nsCRT::strtok( newStr, ", \t", &newStr );
     }
 
     nsMemory::Free(str);
   }
 
   nsAutoString key(aCharCode);
@@ -848,59 +856,65 @@ nsXBLPrototypeHandler::ReportKeyConflict
                                   params, ArrayLength(params),
                                   nsnull, EmptyString(), mLineNumber);
 }
 
 bool
 nsXBLPrototypeHandler::ModifiersMatchMask(nsIDOMUIEvent* aEvent,
                                           bool aIgnoreShiftKey)
 {
-  nsCOMPtr<nsIDOMKeyEvent> key(do_QueryInterface(aEvent));
-  nsCOMPtr<nsIDOMMouseEvent> mouse(do_QueryInterface(aEvent));
+  nsEvent* event = aEvent->GetInternalNSEvent();
+  NS_ENSURE_TRUE(event && NS_IS_INPUT_EVENT(event), false);
+  nsInputEvent* inputEvent = static_cast<nsInputEvent*>(event);
 
-  bool keyPresent;
   if (mKeyMask & cMetaMask) {
-    key ? key->GetMetaKey(&keyPresent) : mouse->GetMetaKey(&keyPresent);
-    if (keyPresent != ((mKeyMask & cMeta) != 0))
+    if (inputEvent->IsMeta() != ((mKeyMask & cMeta) != 0)) {
       return false;
+    }
+  }
+
+  if (mKeyMask & cOSMask) {
+    if (inputEvent->IsOS() != ((mKeyMask & cOS) != 0)) {
+      return false;
+    }
   }
 
   if (mKeyMask & cShiftMask && !aIgnoreShiftKey) {
-    key ? key->GetShiftKey(&keyPresent) : mouse->GetShiftKey(&keyPresent);
-    if (keyPresent != ((mKeyMask & cShift) != 0))
+    if (inputEvent->IsShift() != ((mKeyMask & cShift) != 0)) {
       return false;
+    }
   }
 
   if (mKeyMask & cAltMask) {
-    key ? key->GetAltKey(&keyPresent) : mouse->GetAltKey(&keyPresent);
-    if (keyPresent != ((mKeyMask & cAlt) != 0))
+    if (inputEvent->IsAlt() != ((mKeyMask & cAlt) != 0)) {
       return false;
+    }
   }
 
   if (mKeyMask & cControlMask) {
-    key ? key->GetCtrlKey(&keyPresent) : mouse->GetCtrlKey(&keyPresent);
-    if (keyPresent != ((mKeyMask & cControl) != 0))
+    if (inputEvent->IsControl() != ((mKeyMask & cControl) != 0)) {
       return false;
+    }
   }
 
   return true;
 }
 
 nsresult
 nsXBLPrototypeHandler::Read(nsIScriptContext* aContext, nsIObjectInputStream* aStream)
 {
   nsresult rv = aStream->Read8(&mPhase);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = aStream->Read8(&mKeyMask);
-  NS_ENSURE_SUCCESS(rv, rv);
   rv = aStream->Read8(&mType);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = aStream->Read8(&mMisc);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  rv = aStream->Read32(reinterpret_cast<PRUint32*>(&mKeyMask));
+  NS_ENSURE_SUCCESS(rv, rv);
   PRUint32 detail; 
   rv = aStream->Read32(&detail);
   NS_ENSURE_SUCCESS(rv, rv);
   mDetail = detail;
 
   nsAutoString name;
   rv = aStream->ReadString(name);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -926,22 +940,22 @@ nsXBLPrototypeHandler::Write(nsIScriptCo
   if ((mType & NS_HANDLER_TYPE_XUL) || !mEventName)
     return NS_OK;
 
   XBLBindingSerializeDetails type = XBLBinding_Serialize_Handler;
 
   nsresult rv = aStream->Write8(type);
   rv = aStream->Write8(mPhase);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = aStream->Write8(mKeyMask);
-  NS_ENSURE_SUCCESS(rv, rv);
   rv = aStream->Write8(mType);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = aStream->Write8(mMisc);
   NS_ENSURE_SUCCESS(rv, rv);
+  rv = aStream->Write32(static_cast<PRUint32>(mKeyMask));
+  NS_ENSURE_SUCCESS(rv, rv);
   rv = aStream->Write32(mDetail);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aStream->WriteWStringZ(nsDependentAtomString(mEventName).get());
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aStream->Write32(mLineNumber);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/content/xbl/src/nsXBLPrototypeHandler.h
+++ b/content/xbl/src/nsXBLPrototypeHandler.h
@@ -167,47 +167,50 @@ protected:
   static PRInt32 kAccelKey;
   static PRInt32 kMenuAccessKey;
   static void InitAccessKeys();
 
   static const PRInt32 cShift;
   static const PRInt32 cAlt;
   static const PRInt32 cControl;
   static const PRInt32 cMeta;
+  static const PRInt32 cOS;
 
   static const PRInt32 cShiftMask;
   static const PRInt32 cAltMask;
   static const PRInt32 cControlMask;
   static const PRInt32 cMetaMask;
+  static const PRInt32 cOSMask;
 
   static const PRInt32 cAllModifiers;
 
 protected:
   union {
     nsIWeakReference* mHandlerElement;  // For XUL <key> element handlers. [STRONG]
     PRUnichar*        mHandlerText;     // For XBL handlers (we don't build an
                                         // element for the <handler>, and instead
                                         // we cache the JS text or command name
                                         // that we should use.
   };
 
   PRUint32 mLineNumber;  // The line number we started at in the XBL file
   
   // The following four values make up 32 bits.
   PRUint8 mPhase;            // The phase (capturing, bubbling)
-  PRUint8 mKeyMask;          // Which modifier keys this event handler expects to have down
-                             // in order to be matched.
   PRUint8 mType;             // The type of the handler.  The handler is either a XUL key
                              // handler, an XBL "command" event, or a normal XBL event with
                              // accompanying JavaScript.  The high bit is used to indicate
                              // whether this handler should prevent the default action.
   PRUint8 mMisc;             // Miscellaneous extra information.  For key events,
                              // stores whether or not we're a key code or char code.
                              // For mouse events, stores the clickCount.
 
+  PRInt32 mKeyMask;          // Which modifier keys this event handler expects to have down
+                             // in order to be matched.
+ 
   // The primary filter information for mouse/key events.
   PRInt32 mDetail;           // For key events, contains a charcode or keycode. For
                              // mouse events, stores the button info.
 
   // Prototype handlers are chained. We own the next handler in the chain.
   nsXBLPrototypeHandler* mNextHandler;
   nsCOMPtr<nsIAtom> mEventName; // The type of the event, e.g., "keypress"
   nsRefPtr<nsXBLEventHandler> mHandler;
--- a/layout/xul/base/src/nsMenuBarListener.cpp
+++ b/layout/xul/base/src/nsMenuBarListener.cpp
@@ -28,16 +28,17 @@ using namespace mozilla;
  */
 
 NS_IMPL_ISUPPORTS1(nsMenuBarListener, nsIDOMEventListener)
 
 #define MODIFIER_SHIFT    1
 #define MODIFIER_CONTROL  2
 #define MODIFIER_ALT      4
 #define MODIFIER_META     8
+#define MODIFIER_OS       16
 
 ////////////////////////////////////////////////////////////////////////
 
 PRInt32 nsMenuBarListener::mAccessKey = -1;
 PRUint32 nsMenuBarListener::mAccessKeyMask = 0;
 bool nsMenuBarListener::mAccessKeyFocuses = false;
 
 nsMenuBarListener::nsMenuBarListener(nsMenuBarFrame* aMenuBar) 
@@ -81,16 +82,18 @@ void nsMenuBarListener::InitAccessKey()
   if (mAccessKey == nsIDOMKeyEvent::DOM_VK_SHIFT)
     mAccessKeyMask = MODIFIER_SHIFT;
   else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_CONTROL)
     mAccessKeyMask = MODIFIER_CONTROL;
   else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_ALT)
     mAccessKeyMask = MODIFIER_ALT;
   else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_META)
     mAccessKeyMask = MODIFIER_META;
+  else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_WIN)
+    mAccessKeyMask = MODIFIER_OS;
 
   mAccessKeyFocuses = Preferences::GetBool("ui.key.menuAccessKeyFocuses");
 }
 
 void
 nsMenuBarListener::ToggleMenuActiveState()
 {
   nsMenuFrame* closemenu = mMenuBarFrame->ToggleMenuActiveState();
@@ -265,33 +268,39 @@ nsMenuBarListener::IsAccessKeyPressed(ns
           (modifiers & mAccessKeyMask) &&
           (modifiers & ~(mAccessKeyMask | MODIFIER_SHIFT)) == 0);
 }
 
 PRUint32
 nsMenuBarListener::GetModifiers(nsIDOMKeyEvent* aKeyEvent)
 {
   PRUint32 modifiers = 0;
-  bool modifier;
+  nsInputEvent* inputEvent =
+    static_cast<nsInputEvent*>(aKeyEvent->GetInternalNSEvent());
+  MOZ_ASSERT(inputEvent);
 
-  aKeyEvent->GetShiftKey(&modifier);
-  if (modifier)
+  if (inputEvent->IsShift()) {
     modifiers |= MODIFIER_SHIFT;
+  }
 
-  aKeyEvent->GetCtrlKey(&modifier);
-  if (modifier)
+  if (inputEvent->IsControl()) {
     modifiers |= MODIFIER_CONTROL;
+  }
 
-  aKeyEvent->GetAltKey(&modifier);
-  if (modifier)
+  if (inputEvent->IsAlt()) {
     modifiers |= MODIFIER_ALT;
+  }
 
-  aKeyEvent->GetMetaKey(&modifier);
-  if (modifier)
+  if (inputEvent->IsMeta()) {
     modifiers |= MODIFIER_META;
+  }
+
+  if (inputEvent->IsOS()) {
+    modifiers |= MODIFIER_OS;
+  }
 
   return modifiers;
 }
 
 ////////////////////////////////////////////////////////////////////////
 nsresult
 nsMenuBarListener::KeyDown(nsIDOMEvent* aKeyEvent)
 {
--- a/layout/xul/base/src/nsMenuFrame.cpp
+++ b/layout/xul/base/src/nsMenuFrame.cpp
@@ -1089,41 +1089,49 @@ nsMenuFrame::BuildAcceleratorText(bool a
   char* str = ToNewCString(modifiers);
   char* newStr;
   char* token = nsCRT::strtok(str, ", \t", &newStr);
 
   nsAutoString shiftText;
   nsAutoString altText;
   nsAutoString metaText;
   nsAutoString controlText;
+  nsAutoString osText;
   nsAutoString modifierSeparator;
 
   nsContentUtils::GetShiftText(shiftText);
   nsContentUtils::GetAltText(altText);
   nsContentUtils::GetMetaText(metaText);
   nsContentUtils::GetControlText(controlText);
+  nsContentUtils::GetOSText(osText);
   nsContentUtils::GetModifierSeparatorText(modifierSeparator);
 
   while (token) {
       
     if (PL_strcmp(token, "shift") == 0)
       accelText += shiftText;
     else if (PL_strcmp(token, "alt") == 0) 
       accelText += altText; 
     else if (PL_strcmp(token, "meta") == 0) 
       accelText += metaText; 
+    else if (PL_strcmp(token, "os") == 0)
+      accelText += osText; 
     else if (PL_strcmp(token, "control") == 0) 
       accelText += controlText; 
     else if (PL_strcmp(token, "accel") == 0) {
       switch (accelKey)
       {
         case nsIDOMKeyEvent::DOM_VK_META:
           accelText += metaText;
           break;
 
+        case nsIDOMKeyEvent::DOM_VK_WIN:
+          accelText += osText;
+          break;
+
         case nsIDOMKeyEvent::DOM_VK_ALT:
           accelText += altText;
           break;
 
         case nsIDOMKeyEvent::DOM_VK_CONTROL:
         default:
           accelText += controlText;
           break;
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -1312,23 +1312,23 @@ pref("security.xpconnect.plugin.unrestri
 // security-sensitive dialogs should delay button enabling. In milliseconds.
 pref("security.dialog_enable_delay", 2000);
 
 pref("security.csp.enable", true);
 pref("security.csp.debug", false);
 
 // Modifier key prefs: default to Windows settings,
 // menu access key = alt, accelerator key = control.
-// Use 17 for Ctrl, 18 for Alt, 224 for Meta, 0 for none. Mac settings in macprefs.js
+// Use 17 for Ctrl, 18 for Alt, 224 for Meta, 91 for Win, 0 for none. Mac settings in macprefs.js
 pref("ui.key.accelKey", 17);
 pref("ui.key.menuAccessKey", 18);
 pref("ui.key.generalAccessKey", -1);
 
 // If generalAccessKey is -1, use the following two prefs instead.
-// Use 0 for disabled, 1 for Shift, 2 for Ctrl, 4 for Alt, 8 for Meta
+// Use 0 for disabled, 1 for Shift, 2 for Ctrl, 4 for Alt, 8 for Meta, 16 for Win
 // (values can be combined, e.g. 5 for Alt+Shift)
 pref("ui.key.chromeAccess", 4);
 pref("ui.key.contentAccess", 5);
 
 pref("ui.key.menuAccessKeyFocuses", false); // overridden below
 pref("ui.key.saveLink.shift", true); // true = shift, false = meta
 
 // Disable page loading activity cursor by default.
--- a/toolkit/content/tests/chrome/window_keys.xul
+++ b/toolkit/content/tests/chrome/window_keys.xul
@@ -18,25 +18,34 @@ SimpleTest.waitForExplicitFinish();
 var gExpected = null;
 
 var keysToTest = [
   ["k-v", "V", { } ],
   ["", "V", { shiftKey: true } ],
   ["k-v-scy", "V", { ctrlKey: true } ],
   ["", "V", { altKey: true } ],
   ["", "V", { metaKey: true } ],
+  ["", "V", { osKey: true } ],
   ["k-v-scy", "V", { shiftKey: true, ctrlKey: true } ],
   ["", "V", { shiftKey: true, ctrlKey: true, altKey: true } ],
   ["k-e-y", "E", { } ],
   ["", "E", { shiftKey: true } ],
   ["", "E", { ctrlKey: true } ],
   ["", "E", { altKey: true } ],
   ["", "E", { metaKey: true } ],
+  ["", "E", { osKey: true } ],
   ["k-d-a", "D", { altKey: true } ],
   ["k-8-m", "8", { metaKey: true } ],
+  ["", "8", { metaKey: true, osKey: true } ],
+  ["k-a-o", "A", { osKey: true } ],
+  ["", "A", { osKey: true, metaKey: true } ],
+  ["k-b-myo", "B", { osKey: true } ],
+  ["k-b-myo", "B", { osKey: true, metaKey: true } ],
+  ["k-f-oym", "F", { metaKey: true } ],
+  ["k-f-oym", "F", { metaKey: true, osKey: true } ],
   ["k-c-scaym", "C", { metaKey: true } ],
   ["k-c-scaym", "C", { shiftKey: true, ctrlKey: true, altKey: true, metaKey: true } ],
   ["", "V", { shiftKey: true, ctrlKey: true, altKey: true } ],
   ["k-h-l", "H", { accelKey: true } ],
 //  ["k-j-s", "J", { accessKey: true } ],
   ["", "T", { } ],
   ["scommand", "Y", { } ],
   ["", "U", { } ],
@@ -143,16 +152,19 @@ SimpleTest.waitForFocus(runTest);
 <command id="scommand" oncommand="checkKey(event)"/>
 <command id="scommand-disabled" disabled="true"/>
 
 <keyset id="keyset">
   <key id="k-v" key="v" oncommand="checkKey(event)"/>
   <key id="k-v-scy" key="v" modifiers="shift any control" oncommand="checkKey(event)"/>
   <key id="k-e-y" key="e" modifiers="any" oncommand="checkKey(event)"/>
   <key id="k-8-m" key="8" modifiers="meta" oncommand="checkKey(event)"/>
+  <key id="k-a-o" key="a" modifiers="os" oncommand="checkKey(event)"/>
+  <key id="k-b-myo" key="b" modifiers="meta any os" oncommand="checkKey(event)"/>
+  <key id="k-f-oym" key="f" modifiers="os any meta" oncommand="checkKey(event)"/>
   <key id="k-c-scaym" key="c" modifiers="shift control alt any meta" oncommand="checkKey(event)"/>
   <key id="k-h-l" key="h" modifiers="accel" oncommand="checkKey(event)"/>
   <key id="k-j-s" key="j" modifiers="access" oncommand="checkKey(event)"/>
   <key id="k-t-y" disabled="true" key="t" oncommand="checkKey(event)"/>
   <key id="k-y" key="y" command="scommand"/>
   <key id="k-u" key="u" command="scommand-disabled"/>
 </keyset>
 
--- a/toolkit/locales/en-US/chrome/global-platform/mac/platformKeys.properties
+++ b/toolkit/locales/en-US/chrome/global-platform/mac/platformKeys.properties
@@ -7,16 +7,19 @@
 #these are used in XP menus to show keyboard shortcuts
 
 #the shift key - open up arrow symbol (ctrl-e)
 VK_SHIFT=\u21e7
 
 #the command key - clover leaf symbol (ctrl-q)
 VK_META=\u2318
 
+#the win key - never generated by native key event
+VK_WIN=win
+
 #the option/alt key - splitting tracks symbol (ctrl-g)
 VK_ALT=\u2325
 
 #the control key. hat symbol (ctrl-f)
 VK_CONTROL=\u2303
 
 #the separator character used between modifiers (none on Mac OS)
 MODIFIER_SEPARATOR=
--- a/toolkit/locales/en-US/chrome/global-platform/unix/platformKeys.properties
+++ b/toolkit/locales/en-US/chrome/global-platform/unix/platformKeys.properties
@@ -7,16 +7,19 @@
 #these are used in XP menus to show keyboard shortcuts
 
 #the shift key
 VK_SHIFT=Shift
 
 #the command key
 VK_META=Meta
 
+#the win key (Super key and Hyper keys are mapped to DOM Win key)
+VK_WIN=Win
+
 #the alt key
 VK_ALT=Alt
 
 #the control key
 VK_CONTROL=Ctrl
 
 #the separator character used between modifiers 
 MODIFIER_SEPARATOR=+
--- a/toolkit/locales/en-US/chrome/global-platform/win/platformKeys.properties
+++ b/toolkit/locales/en-US/chrome/global-platform/win/platformKeys.properties
@@ -7,16 +7,19 @@
 #these are used in XP menus to show keyboard shortcuts
 
 #the shift key
 VK_SHIFT=Shift
 
 #the command key
 VK_META=Meta
 
+#the win key
+VK_WIN=Win
+
 #the alt key
 VK_ALT=Alt
 
 #the control key
 VK_CONTROL=Ctrl
 
 #the separator character used between modifiers 
 MODIFIER_SEPARATOR=+
--- a/widget/gtk2/nsGtkKeyUtils.cpp
+++ b/widget/gtk2/nsGtkKeyUtils.cpp
@@ -1181,19 +1181,21 @@ KeymapWrapper::InitKeypressEvent(nsKeyEv
              "keyCode=0x%02X, charCode=0x%08X",
              this, aKeyEvent.keyCode, aKeyEvent.charCode));
         return;
     }
 
     // If the event causes inputting a character, keyCode must be zero.
     aKeyEvent.keyCode = 0;
 
-    // If Ctrl or Alt or Meta is pressed, we need to append the key details
-    // for handling shortcut key.  Otherwise, we have no additional work.
-    if (!aKeyEvent.IsControl() && !aKeyEvent.IsAlt() && !aKeyEvent.IsMeta()) {
+    // If Ctrl or Alt or Meta or OS is pressed, we need to append the key
+    // details for handling shortcut key.  Otherwise, we have no additional
+    // work.
+    if (!aKeyEvent.IsControl() && !aKeyEvent.IsAlt() &&
+        !aKeyEvent.IsMeta() && !aKeyEvent.IsOS()) {
         PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
             ("KeymapWrapper(%p): InitKeypressEvent, "
              "keyCode=0x%02X, charCode=0x%08X",
              this, aKeyEvent.keyCode, aKeyEvent.charCode));
         return;
     }
 
     gint level = GetKeyLevel(aGdkKeyEvent);
--- a/widget/nsGUIEvent.h
+++ b/widget/nsGUIEvent.h
@@ -1797,16 +1797,27 @@ enum nsDragDropEventStatus {
   /// The event is a enter
   nsDragDropEventStatus_eDragEntered,            
   /// The event is exit
   nsDragDropEventStatus_eDragExited, 
   /// The event is drop
   nsDragDropEventStatus_eDrop  
 };
 
+#define NS_IS_INPUT_EVENT(evnt) \
+       (((evnt)->eventStructType == NS_INPUT_EVENT) || \
+        ((evnt)->eventStructType == NS_ACCESSIBLE_EVENT) || \
+        ((evnt)->eventStructType == NS_MOUSE_EVENT) || \
+        ((evnt)->eventStructType == NS_KEY_EVENT) || \
+        ((evnt)->eventStructType == NS_TEXT_EVENT) || \
+        ((evnt)->eventStructType == NS_TOUCH_EVENT) || \
+        ((evnt)->eventStructType == NS_DRAG_EVENT) || \
+        ((evnt)->eventStructType == NS_MOUSE_SCROLL_EVENT) || \
+        ((evnt)->eventStructType == NS_MOZTOUCH_EVENT) || \
+        ((evnt)->eventStructType == NS_SIMPLE_GESTURE_EVENT))
 
 #define NS_IS_MOUSE_EVENT(evnt) \
        (((evnt)->message == NS_MOUSE_BUTTON_DOWN) || \
         ((evnt)->message == NS_MOUSE_BUTTON_UP) || \
         ((evnt)->message == NS_MOUSE_CLICK) || \
         ((evnt)->message == NS_MOUSE_DOUBLECLICK) || \
         ((evnt)->message == NS_MOUSE_ENTER) || \
         ((evnt)->message == NS_MOUSE_EXIT) || \
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -6378,17 +6378,17 @@ LRESULT nsWindow::OnKeyDown(const MSG &a
   bool isDeadKey = gKbdLayout.IsDeadKey(virtualKeyCode, aModKeyState);
   PRUint32 extraFlags = (noDefault ? NS_EVENT_FLAG_NO_DEFAULT : 0);
   MSG msg;
   BOOL gotMsg = aFakeCharMessage ||
     ::PeekMessageW(&msg, mWnd, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
   // Enter and backspace are always handled here to avoid for example the
   // confusion between ctrl-enter and ctrl-J.
   if (DOMKeyCode == NS_VK_RETURN || DOMKeyCode == NS_VK_BACK ||
-      ((aModKeyState.IsControl() || aModKeyState.IsAlt())
+      ((aModKeyState.IsControl() || aModKeyState.IsAlt() || aModKeyState.IsWin())
        && !isDeadKey && KeyboardLayout::IsPrintableCharKey(virtualKeyCode)))
   {
     // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
     // They can be more than one because of:
     //  * Dead-keys not pairing with base character
     //  * Some keyboard layouts may map up to 4 characters to the single key
     bool anyCharMessagesRemoved = false;
 
@@ -6467,17 +6467,18 @@ LRESULT nsWindow::OnKeyDown(const MSG &a
     BOOL result = OnChar(msg, nativeKey, aModKeyState, nsnull, extraFlags);
     // If a syschar keypress wasn't processed, Windows may want to
     // handle it to activate a native menu.
     if (!result && msg.message == WM_SYSCHAR)
       ::DefWindowProcW(mWnd, msg.message, msg.wParam, msg.lParam);
     return result;
   }
   else if (!aModKeyState.IsControl() && !aModKeyState.IsAlt() &&
-           KeyboardLayout::IsPrintableCharKey(virtualKeyCode)) {
+            !aModKeyState.IsWin() &&
+            KeyboardLayout::IsPrintableCharKey(virtualKeyCode)) {
     // If this is simple KeyDown event but next message is not WM_CHAR,
     // this event may not input text, so we should ignore this event.
     // See bug 314130.
     return PluginHasFocus() && noDefault;
   }
 
   if (isDeadKey) {
     return PluginHasFocus() && noDefault;