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 102853 372c0dbbfb5b6b305579ee85b442683aa6046d6f
parent 102852 90f71c5e14d88a7cb054144af7924fddd9f3d7d3
child 102854 ae94d3a4497e5962de06dd58ded2b8376beb9765
push idunknown
push userunknown
push dateunknown
reviewerssmaug, enn
bugs751749
milestone17.0a1
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;