Package: iceweasel
Version: 15.0-1
Severity: normal
Tags: patch

Dear Maintainer,
Since version 13, iceweasel don't allow use the Win/Super/Meta key for
keyboard shortcuts. This problem is present only on gnu/linux because of
changes made by Mozilla, which were described by the developer Masayuki
Nakano (masayuki) in the same error repoted [1]. I have applied patchs
proposed by masayuki to iceweasel from experimental branch and after
fix some conflict in nsMenuBarListener.cpp and nsXBLPrototypeHandler.cpp
in my iceweasel Win/Super/Meta key works again.
I've attached the patch with the adjustments I made to the version 15.


[1] https://bugzilla.mozilla.org/show_bug.cgi?id=751749

-- Package-specific info:

Name: Adblock Plus
Location:
${PROFILE_EXTENSIONS}/{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}.xpi
Status: user-disabled

Name: CacheViewer
Location: 
/usr/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}/{71328583-3CA7-4809-B4BA-570A85818FBB}
Package: xul-ext-cacheviewer
Status: app-disabled

Name: Default theme
Location: /usr/lib/iceweasel/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}
Package: iceweasel
Status: user-disabled

Name: Diccionario de Español/España
Location: ${PROFILE_EXTENSIONS}/es...@dictionaries.addons.mozilla.org
Status: enabled

Name: DownThemAll!
Location:
${PROFILE_EXTENSIONS}/{DDC359D1-844A-42a7-9AA1-88A850A938A8}.xpi
Status: enabled

Name: Elementary Style userstyle
Status: user-disabled

Name: Find & Add-on bar transparent userstyle
Status: enabled

Name: Firebug
Location: 
/usr/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}/fire...@software.joehewitt.com
Package: xul-ext-firebug
Status: user-disabled

Name: Flashblock
Location:
${PROFILE_EXTENSIONS}/{3d7eb24f-2740-49df-8937-200b1cc08f8a}.xpi
Status: enabled

Name: FlashGot
Location:
${PROFILE_EXTENSIONS}/{19503e42-ca3c-4c27-b1e2-9cdb2170ee34}.xpi
Status: enabled

Name: gTranslate
Location:
${PROFILE_EXTENSIONS}/{aff87fa2-a58e-4edd-b852-0a20203c1e17}.xpi
Status: enabled

Name: ImgLikeOpera
Location: ${PROFILE_EXTENSIONS}/imglikeop...@imfo.ru.xpi
Status: enabled

Name: keyconfig
Location: ${PROFILE_EXTENSIONS}/keycon...@dorando.xpi
Status: enabled

Name: Live HTTP headers
Location: ${PROFILE_EXTENSIONS}/{8f8fe09b-0bd3-4470-bc1b-8cad42b8203a}
Status: user-disabled

Name: PhZilla
Location: ${PROFILE_EXTENSIONS}/amin.eft_phpr...@gmail.com
Status: enabled

Name: Proxy Selector
Location: ${PROFILE_EXTENSIONS}/proxyselec...@mozilla.org.xpi
Status: enabled

Name: RSS Icon
Location: ${PROFILE_EXTENSIONS}/kitsune...@gmail.com.xpi
Status: enabled

Name: Silvermel theme
Location: ${PROFILE_EXTENSIONS}/silver...@pardal.de.xpi
Status: enabled

Name: Silvermel and Charamel XT
Location: ${PROFILE_EXTENSIONS}/silverme...@pardal.de.xpi
Status: enabled

Name: Stylish
Location:
${PROFILE_EXTENSIONS}/{46551EC9-40F0-4e47-8E18-8E5CF550CFB8}.xpi
Status: enabled

Name: Undo Closed Tabs Button
Location: ${PROFILE_EXTENSIONS}/undoclosedtabsbut...@supernova00.biz.xpi
Status: enabled

Name: United States English Spellchecker
Location: ${PROFILE_EXTENSIONS}/en...@dictionaries.addons.mozilla.org
Status: enabled

Name: UnMHT
Location:
${PROFILE_EXTENSIONS}/{f759ca51-3a91-4dd1-ae78-9db5eee9ebf0}.xpi
Status: user-disabled

Name: User Agent Switcher
Location:
${PROFILE_EXTENSIONS}/{e968fc70-8f95-4ab9-9e79-304de2a71ee1}.xpi
Status: user-disabled

Name: Zotero
Location: 
/usr/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}/zot...@chnm.gmu.edu
Package: xul-ext-zotero
Status: enabled

-- Plugins information
Name: DivX Browser Plug-In
Location: /usr/lib/mozilla/plugins/gecko-mediaplayer-dvx.so
Package: gecko-mediaplayer
Status: enabled

Name: Gnome Shell Integration
Location: /usr/lib/mozilla/plugins/libgnome-shell-browser-plugin.so
Package: gnome-shell
Status: enabled

Name: iTunes Application Detector
Location: /usr/lib/mozilla/plugins/librhythmbox-itms-detection-plugin.so
Package: rhythmbox-plugins
Status: enabled

Name: Java(TM) Plug-in 1.6.0_25
Location: /usr/lib/jvm/jdk1.6.0_25/jre/lib/i386/libnpjp2.so
Status: disabled

Name: mplayerplug-in is now gecko-mediaplayer 1.0.6
Location: /usr/lib/mozilla/plugins/gecko-mediaplayer.so
Package: gecko-mediaplayer
Status: enabled

Name: QuickTime Plug-in 7.6.9
Location: /usr/lib/mozilla/plugins/gecko-mediaplayer-qt.so
Package: gecko-mediaplayer
Status: enabled

Name: RealPlayer 9
Location: /usr/lib/mozilla/plugins/gecko-mediaplayer-rm.so
Package: gecko-mediaplayer
Status: enabled

Name: Shockwave Flash
Location: /usr/lib/flashplayer-mozilla/libflashplayer.so
Package: flashplayer-mozilla
Status: enabled

Name: Windows Media Player Plug-in
Location: /usr/lib/mozilla/plugins/gecko-mediaplayer-wmp.so
Package: gecko-mediaplayer
Status: enabled


-- Addons package information
ii  flashplayer-mo 3:11.2.202.2 i386         Macromedia Flash Player.
ii  gecko-mediapla 1.0.6-1      i386         Multimedia plug-in for
Gecko brow
ii  gnome-shell    3.4.2-1      i386         graphical shell for the
GNOME des
ii  iceweasel      15.0-1~msg+2 i386         Web browser based on
Firefox
ii  rhythmbox-plug 2.97-2.1     i386         plugins for rhythmbox music
playe
ii  xul-ext-cachev 0.6.3-1      all          this extenion is GUI
Front-end of
ii  xul-ext-firebu 1.9.2~b2-1   all          web development plugin for
Icewea
ii  xul-ext-zotero 3.0.7-1      all          Iceweasel extension to
organize a

-- System Information:
Debian Release: wheezy/sid
  APT prefers testing
  APT policy: (800, 'testing')
Architecture: i386 (i686)

Kernel: Linux 3.2.0-3-686-pae (SMP w/2 CPU cores)
Locale: LANG=en_US.utf8, LC_CTYPE=en_US.utf8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages iceweasel depends on:
ii  debianutils         4.3.2
ii  fontconfig          2.9.0-7
ii  libc6               2.13-35
ii  libgdk-pixbuf2.0-0  2.26.1-1
ii  libglib2.0-0        2.32.3-1
ii  libgtk2.0-0         2.24.10-2
ii  libnspr4            2:4.9.1-1
ii  libnspr4-0d         2:4.9.1-1
ii  libsqlite3-0        3.7.13-1
ii  libstdc++6          4.7.1-2
ii  procps              1:3.3.3-2
ii  xulrunner-15.0      15.0-1~msg+2

iceweasel recommends no packages.

Versions of packages iceweasel suggests:
pn  fonts-stix | otf-stix  <none>
ii  libgssapi-krb5-2       1.10.1+dfsg-2
pn  mozplugger             <none>

Versions of packages xulrunner-15.0 depends on:
ii  libasound2                1.0.25-4
ii  libatk1.0-0               2.4.0-2
ii  libbz2-1.0                1.0.6-4
ii  libc6                     2.13-35
ii  libcairo2                 1.12.2-2
ii  libdbus-1-3               1.6.0-1
ii  libdbus-glib-1-2          0.100-1
ii  libevent-2.0-5            2.0.19-stable-3
ii  libfontconfig1            2.9.0-7
ii  libfreetype6              2.4.9-1
ii  libgcc1                   1:4.7.1-2
ii  libgdk-pixbuf2.0-0        2.26.1-1
ii  libglib2.0-0              2.32.3-1
ii  libgtk2.0-0               2.24.10-2
ii  libhunspell-1.3-0         1.3.2-4
ii  libjpeg8                  8d-1
ii  libmozjs15d               15.0-1~msg+2
ii  libnotify4                0.7.5-1
ii  libnspr4                  2:4.9.1-1
ii  libnspr4-0d               2:4.9.1-1
ii  libnss3                   2:3.13.5-1
ii  libnss3-1d                2:3.13.5-1
ii  libpango1.0-0             1.30.0-1
ii  libpixman-1-0             0.26.0-3
ii  libsqlite3-0              3.7.13-1
ii  libstartup-notification0  0.12-1
ii  libstdc++6                4.7.1-2
ii  libvpx1                   1.1.0-1
ii  libx11-6                  2:1.5.0-1
ii  libxext6                  2:1.3.1-2
ii  libxrender1               1:0.9.7-1
ii  libxt6                    1:1.1.3-1
ii  zlib1g                    1:1.2.7.dfsg-13

Versions of packages xulrunner-15.0 suggests:
ii  libcanberra0  0.28-4
ii  libgnomeui-0  2.24.5-2

-- no debconf information
-- 
Ing. Marcel Sánchez Góngora
Dpto Gestión Documental - CENIA/UCI
I think... I think it's in my basement... Let me go upstairs and check.
     ** Escher


10mo. ANIVERSARIO DE LA CREACION DE LA UNIVERSIDAD DE LAS CIENCIAS 
INFORMATICAS...
CONECTADOS AL FUTURO, CONECTADOS A LA REVOLUCION

http://www.uci.cu
http://www.facebook.com/universidad.uci
http://www.flickr.com/photos/universidad_uci
From: Masayuki Nakano <masay...@d-toybox.com>
Date: Mon, 25 Jun 2012 16:49:21 +0900
Subject: Bug 751749 - cannot configure keyboard shortcuts to use Meta modifier
 instead of Alt 

---

--- a/accessible/src/generic/Accessible.h
+++ b/accessible/src/generic/Accessible.h
@@ -904,6 +904,7 @@
   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) :
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1859,6 +1859,7 @@
   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);
 
@@ -2131,6 +2132,7 @@
   static nsString* sShiftText;
   static nsString* sControlText;
   static nsString* sMetaText;
+  static nsString* sOSText;
   static nsString* sAltText;
   static nsString* sModifierSeparator;
 };
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -235,6 +235,7 @@
 nsString* nsContentUtils::sShiftText = nsnull;
 nsString* nsContentUtils::sControlText = nsnull;
 nsString* nsContentUtils::sMetaText = nsnull;
+nsString* nsContentUtils::sOSText = nsnull;
 nsString* nsContentUtils::sAltText = nsnull;
 nsString* nsContentUtils::sModifierSeparator = nsnull;
 
@@ -452,6 +453,15 @@
 }
 
 void
+nsContentUtils::GetOSText(nsAString& text)
+{
+  if (!sOSText) {
+    InitializeModifierStrings();
+  }
+  text.Assign(*sOSText);
+}
+
+void
 nsContentUtils::GetAltText(nsAString& text)
 {
   if (!sAltText)
@@ -483,6 +493,7 @@
   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;
@@ -490,6 +501,7 @@
     //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));
@@ -497,6 +509,7 @@
   //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);  
@@ -1453,6 +1466,8 @@
   sControlText = nsnull;
   delete sMetaText;  
   sMetaText = nsnull;
+  delete sOSText;
+  sOSText = nsnull;
   delete sAltText;  
   sAltText = nsnull;
   delete sModifierSeparator;
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -267,6 +267,7 @@
 #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)
@@ -291,6 +292,7 @@
     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;
   }
 
@@ -1168,6 +1170,8 @@
         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 ||
@@ -1525,6 +1529,10 @@
     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);
--- a/content/xbl/src/nsXBLPrototypeHandler.cpp
+++ b/content/xbl/src/nsXBLPrototypeHandler.cpp
@@ -63,13 +63,16 @@
 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,
@@ -493,6 +496,8 @@
     return NS_ERROR_FAILURE;
   }
 
+  // XXX We should use widget::Modifiers for supporting all modifiers.
+
   bool isAlt = false;
   bool isControl = false;
   bool isShift = false;
@@ -643,11 +648,12 @@
   {
     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:
@@ -754,6 +760,8 @@
         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)
@@ -761,7 +769,7 @@
       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 );
     }
@@ -850,32 +858,39 @@
 nsXBLPrototypeHandler::ModifiersMatchMask(nsIDOMUIEvent* aEvent,
                                           bool aIgnoreShiftKey)
 {
-  nsCOMPtr<nsIDOMKeyEvent> key(do_QueryInterface(aEvent));
-  nsCOMPtr<nsIDOMMouseEvent> mouse(do_QueryInterface(aEvent));
+  nsCOMPtr<nsIPrivateDOMEvent> pEvent = do_QueryInterface(aEvent);  
+  nsEvent* event = pEvent->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;
@@ -886,13 +901,13 @@
 {
   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);
@@ -928,12 +943,12 @@
   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);
 
--- a/content/xbl/src/nsXBLPrototypeHandler.h
+++ b/content/xbl/src/nsXBLPrototypeHandler.h
@@ -172,11 +172,13 @@
   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;
 
@@ -193,8 +195,6 @@
   
   // 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
@@ -203,6 +203,9 @@
                              // 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.
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -5099,6 +5099,7 @@
 
   switch (nativeKeyEvent->keyCode) {
     case nsIDOMKeyEvent::DOM_VK_META:
+    case nsIDOMKeyEvent::DOM_VK_WIN:
     case nsIDOMKeyEvent::DOM_VK_SHIFT:
     case nsIDOMKeyEvent::DOM_VK_CONTROL:
     case nsIDOMKeyEvent::DOM_VK_ALT:
@@ -5106,7 +5107,7 @@
       return NS_OK;
     case nsIDOMKeyEvent::DOM_VK_BACK_SPACE:
       if (nativeKeyEvent->IsControl() || nativeKeyEvent->IsAlt() ||
-          nativeKeyEvent->IsMeta()) {
+          nativeKeyEvent->IsMeta() || nativeKeyEvent->IsOS()) {
         return NS_OK;
       }
       DeleteSelection(nsIEditor::ePrevious, nsIEditor::eStrip);
@@ -5117,7 +5118,8 @@
       // modifies what delete does (cmd_cut in this case).
       // bailing here to allow the keybindings to do the cut.
       if (nativeKeyEvent->IsShift() || nativeKeyEvent->IsControl() ||
-          nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta()) {
+          nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta() ||
+          nativeKeyEvent->IsOS()) {
         return NS_OK;
       }
       DeleteSelection(nsIEditor::eNext, nsIEditor::eStrip);
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -598,6 +598,7 @@
 
   switch (nativeKeyEvent->keyCode) {
     case nsIDOMKeyEvent::DOM_VK_META:
+    case nsIDOMKeyEvent::DOM_VK_WIN:
     case nsIDOMKeyEvent::DOM_VK_SHIFT:
     case nsIDOMKeyEvent::DOM_VK_CONTROL:
     case nsIDOMKeyEvent::DOM_VK_ALT:
@@ -618,7 +619,7 @@
       }
 
       if (nativeKeyEvent->IsControl() || nativeKeyEvent->IsAlt() ||
-          nativeKeyEvent->IsMeta()) {
+          nativeKeyEvent->IsMeta() || nativeKeyEvent->IsOS()) {
         return NS_OK;
       }
 
@@ -668,7 +669,7 @@
     case nsIDOMKeyEvent::DOM_VK_RETURN:
     case nsIDOMKeyEvent::DOM_VK_ENTER:
       if (nativeKeyEvent->IsControl() || nativeKeyEvent->IsAlt() ||
-          nativeKeyEvent->IsMeta()) {
+          nativeKeyEvent->IsMeta() || nativeKeyEvent->IsOS()) {
         return NS_OK;
       }
       aKeyEvent->PreventDefault(); // consumed
@@ -683,7 +684,8 @@
   // NOTE: On some keyboard layout, some characters are inputted with Control
   // key or Alt key, but at that time, widget sets FALSE to these keys.
   if (nativeKeyEvent->charCode == 0 || nativeKeyEvent->IsControl() ||
-      nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta()) {
+      nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta() ||
+      nativeKeyEvent->IsOS()) {
     // we don't PreventDefault() here or keybindings like control-x won't work
     return NS_OK;
   }
--- a/editor/libeditor/html/tests/test_htmleditor_keyevent_handling.html
+++ b/editor/libeditor/html/tests/test_htmleditor_keyevent_handling.html
@@ -137,6 +137,10 @@
     check(aDescription + "Meta", true, true, !aIsReadonly);
 
     reset("");
+    synthesizeKey("VK_WIN", { type: "keypress" });
+    check(aDescription + "OS", true, true, !aIsReadonly);
+
+    reset("");
     synthesizeKey("VK_SHIFT", { type: "keypress" });
     check(aDescription + "Shift", true, true, !aIsReadonly);
 
@@ -176,6 +180,10 @@
     synthesizeKey("VK_BACK_SPACE", { metaKey: true });
     check(aDescription + "Meta+Backspace", true, true, aIsReadonly);
 
+    reset("");
+    synthesizeKey("VK_BACK_SPACE", { osKey: true });
+    check(aDescription + "OS+Backspace", true, true, aIsReadonly);
+
     // Delete key:
     //   If editor is readonly, it doesn't consume.
     //   If editor is editable, delete is consumed.
@@ -200,6 +208,10 @@
     synthesizeKey("VK_DELETE", { metaKey: true });
     check(aDescription + "Meta+Delete", true, true, false);
 
+    reset("");
+    synthesizeKey("VK_DELETE", { osKey: true });
+    check(aDescription + "OS+Delete", true, true, false);
+
     // Return key:
     //   If editor is readonly, it doesn't consume.
     //   If editor is editable and not single line editor, it consumes Return
@@ -234,6 +246,11 @@
     check(aDescription + "Meta+Return", true, true, false);
     is(aElement.innerHTML, "a", aDescription + "Meta+Return");
 
+    reset("a");
+    synthesizeKey("VK_RETURN", { osKey: true });
+    check(aDescription + "OS+Return", true, true, false);
+    is(aElement.innerHTML, "a", aDescription + "OS+Return");
+
     // Enter key (same as Return key):
     //   If editor is readonly, it doesn't consume.
     //   If editor is editable and not single line editor, it consumes Return
@@ -268,6 +285,11 @@
     check(aDescription + "Meta+Enter", true, true, false);
     is(aElement.innerHTML, "a", aDescription + "Meta+Enter");
 
+    reset("a");
+    synthesizeKey("VK_ENTER", { osKey: true });
+    check(aDescription + "OS+Enter", true, true, false);
+    is(aElement.innerHTML, "a", aDescription + "OS+Enter");
+
     // Tab key:
     //   If editor is tabbable, editor doesn't consume all tab key events.
     //   Otherwise, editor consumes tab key event without any modifier keys.
@@ -311,6 +333,13 @@
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Meta+Tab)");
 
+    reset("a");
+    synthesizeKey("VK_TAB", { osKey: true });
+    check(aDescription + "OS+Tab", true, true, false);
+    is(aElement.innerHTML, "a", aDescription + "OS+Tab");
+    is(fm.focusedElement, aElement,
+       aDescription + "focus moved unexpectedly (OS+Tab)");
+
     // Indent/Outdent tests:
     // UL
     resetForIndent("<ul><li id=\"target\">ul list item</li></ul>");
@@ -372,6 +401,14 @@
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Meta+Tab on UL)");
 
+    resetForIndent("<ul><li id=\"target\">ul list item</li></ul>");
+    synthesizeKey("VK_TAB", { osKey: true });
+    check(aDescription + "OS+Tab on UL", true, true, false);
+    is(aElement.innerHTML, "<ul><li id=\"target\">ul list item</li></ul>",
+       aDescription + "OS+Tab on UL");
+    is(fm.focusedElement, aElement,
+       aDescription + "focus moved unexpectedly (OS+Tab on UL)");
+
     // OL
     resetForIndent("<ol><li id=\"target\">ol list item</li></ol>");
     synthesizeKey("VK_TAB", { });
@@ -432,6 +469,14 @@
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Meta+Tab on OL)");
 
+    resetForIndent("<ol><li id=\"target\">ol list item</li></ol>");
+    synthesizeKey("VK_TAB", { osKey: true });
+    check(aDescription + "OS+Tab on OL", true, true, false);
+    is(aElement.innerHTML, "<ol><li id=\"target\">ol list item</li></ol>",
+       aDescription + "OS+Tab on OL");
+    is(fm.focusedElement, aElement,
+       aDescription + "focus moved unexpectedly (OS+Tab on OL)");
+
     // TD
     resetForIndent("<table><tr><td id=\"target\">td</td></tr></table>");
     synthesizeKey("VK_TAB", { });
@@ -494,6 +539,15 @@
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Meta+Tab on TD)");
 
+    resetForIndent("<table><tr><td id=\"target\">td</td></tr></table>");
+    synthesizeKey("VK_TAB", { osKey: true });
+    check(aDescription + "OS+Tab on TD", true, true, false);
+    is(aElement.innerHTML,
+       "<table><tbody><tr><td id=\"target\">td</td></tr></tbody></table>",
+       aDescription + "OS+Tab on TD");
+    is(fm.focusedElement, aElement,
+       aDescription + "focus moved unexpectedly (OS+Tab on TD)");
+
     // TH
     resetForIndent("<table><tr><th id=\"target\">th</th></tr></table>");
     synthesizeKey("VK_TAB", { });
@@ -556,6 +610,15 @@
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Meta+Tab on TH)");
 
+    resetForIndent("<table><tr><th id=\"target\">th</th></tr></table>");
+    synthesizeKey("VK_TAB", { osKey: true });
+    check(aDescription + "OS+Tab on TH", true, true, false);
+    is(aElement.innerHTML,
+       "<table><tbody><tr><th id=\"target\">th</th></tr></tbody></table>",
+       aDescription + "OS+Tab on TH");
+    is(fm.focusedElement, aElement,
+       aDescription + "focus moved unexpectedly (OS+Tab on TH)");
+
     // Esc key:
     //   In all cases, esc key events are not consumed
     reset("abc");
@@ -578,6 +641,10 @@
     synthesizeKey("VK_ESCAPE", { metaKey: true });
     check(aDescription + "Meta+Esc", true, true, false);
 
+    reset("abc");
+    synthesizeKey("VK_ESCAPE", { osKey: true });
+    check(aDescription + "OS+Esc", true, true, false);
+
     // typical typing tests:
     reset("");
     synthesizeKey("M", { shiftKey: true });
--- a/editor/libeditor/text/nsPlaintextEditor.cpp
+++ b/editor/libeditor/text/nsPlaintextEditor.cpp
@@ -344,6 +344,7 @@
 
   switch (nativeKeyEvent->keyCode) {
     case nsIDOMKeyEvent::DOM_VK_META:
+    case nsIDOMKeyEvent::DOM_VK_WIN:
     case nsIDOMKeyEvent::DOM_VK_SHIFT:
     case nsIDOMKeyEvent::DOM_VK_CONTROL:
     case nsIDOMKeyEvent::DOM_VK_ALT:
@@ -357,7 +358,8 @@
       }
 
       if (nativeKeyEvent->IsShift() || nativeKeyEvent->IsControl() ||
-          nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta()) {
+          nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta() ||
+          nativeKeyEvent->IsOS()) {
         return NS_OK;
       }
 
@@ -368,7 +370,8 @@
     case nsIDOMKeyEvent::DOM_VK_RETURN:
     case nsIDOMKeyEvent::DOM_VK_ENTER:
       if (IsSingleLineEditor() || nativeKeyEvent->IsControl() ||
-          nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta()) {
+          nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta() ||
+          nativeKeyEvent->IsOS()) {
         return NS_OK;
       }
       aKeyEvent->PreventDefault();
@@ -378,7 +381,8 @@
   // NOTE: On some keyboard layout, some characters are inputted with Control
   // key or Alt key, but at that time, widget sets FALSE to these keys.
   if (nativeKeyEvent->charCode == 0 || nativeKeyEvent->IsControl() ||
-      nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta()) {
+      nativeKeyEvent->IsAlt() || nativeKeyEvent->IsMeta() ||
+      nativeKeyEvent->IsOS()) {
     // we don't PreventDefault() here or keybindings like control-x won't work
     return NS_OK;
   }
--- a/editor/libeditor/text/tests/test_texteditor_keyevent_handling.html
+++ b/editor/libeditor/text/tests/test_texteditor_keyevent_handling.html
@@ -124,6 +124,10 @@
     check(aDescription + "Meta", true, true, !aIsReadonly);
 
     reset("");
+    synthesizeKey("VK_WIN", { type: "keypress" });
+    check(aDescription + "OS", true, true, !aIsReadonly);
+
+    reset("");
     synthesizeKey("VK_SHIFT", { type: "keypress" });
     check(aDescription + "Shift", true, true, !aIsReadonly);
 
@@ -169,6 +173,10 @@
     synthesizeKey("VK_BACK_SPACE", { metaKey: true });
     check(aDescription + "Meta+Backspace", true, true, aIsReadonly);
 
+    reset("");
+    synthesizeKey("VK_BACK_SPACE", { osKey: true });
+    check(aDescription + "OS+Backspace", true, true, aIsReadonly);
+
     // Delete key:
     //   If editor is readonly, it doesn't consume.
     //   If editor is editable, delete is consumed.
@@ -206,6 +214,11 @@
     check(aDescription + "Meta+Delete",
           true, true, kIsLinux);
 
+    reset("");
+    synthesizeKey("VK_DELETE", { osKey: true });
+    check(aDescription + "OS+Delete",
+          true, true, false);
+
     // XXX input.value returns "\n" when it's empty, so, we should use dummy
     // value ("a") for the following tests.
 
@@ -243,6 +256,11 @@
     check(aDescription + "Meta+Return", true, true, false);
     is(aElement.value, "a", aDescription + "Meta+Return");
 
+    reset("a");
+    synthesizeKey("VK_RETURN", { osKey: true });
+    check(aDescription + "OS+Return", true, true, false);
+    is(aElement.value, "a", aDescription + "OS+Return");
+
     // Enter key (same as Return key):
     //   If editor is readonly, it doesn't consume.
     //   If editor is editable and not single line editor, it consumes Return
@@ -277,6 +295,11 @@
     check(aDescription + "Meta+Enter", true, true, false);
     is(aElement.value, "a", aDescription + "Meta+Enter");
 
+    reset("a");
+    synthesizeKey("VK_ENTER", { osKey: true });
+    check(aDescription + "OS+Enter", true, true, false);
+    is(aElement.value, "a", aDescription + "OS+Enter");
+
     // Tab key:
     //   If editor is tabbable, editor doesn't consume all tab key events.
     //   Otherwise, editor consumes tab key event without any modifier keys.
@@ -330,6 +353,13 @@
     is(fm.focusedElement, aElement,
        aDescription + "focus moved unexpectedly (Meta+Tab)");
 
+    reset("a");
+    synthesizeKey("VK_TAB", { osKey: true });
+    check(aDescription + "OS+Tab", true, true, false);
+    is(aElement.value, "a", aDescription + "OS+Tab");
+    is(fm.focusedElement, aElement,
+       aDescription + "focus moved unexpectedly (OS+Tab)");
+
     // Esc key:
     //   In all cases, esc key events are not consumed
     reset("abc");
@@ -352,6 +382,10 @@
     synthesizeKey("VK_ESCAPE", { metaKey: true });
     check(aDescription + "Meta+Esc", true, true, false);
 
+    reset("abc");
+    synthesizeKey("VK_ESCAPE", { osKey: true });
+    check(aDescription + "OS+Esc", true, true, false);
+
     // typical typing tests:
     reset("");
     synthesizeKey("M", { shiftKey: true });
--- a/layout/xul/base/src/nsMenuBarListener.cpp
+++ b/layout/xul/base/src/nsMenuBarListener.cpp
@@ -8,6 +8,7 @@
 #include "nsMenuPopupFrame.h"
 #include "nsIDOMNSEvent.h"
 #include "nsGUIEvent.h"
+#include "nsIPrivateDOMEvent.h"
 
 // Drag & Drop, Clipboard
 #include "nsIServiceManager.h"
@@ -33,6 +34,7 @@
 #define MODIFIER_CONTROL  2
 #define MODIFIER_ALT      4
 #define MODIFIER_META     8
+#define MODIFIER_OS       16
 
 ////////////////////////////////////////////////////////////////////////
 
@@ -86,6 +88,8 @@
     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");
 }
@@ -270,23 +274,30 @@
 nsMenuBarListener::GetModifiers(nsIDOMKeyEvent* aKeyEvent)
 {
   PRUint32 modifiers = 0;
-  bool modifier;
+  nsCOMPtr<nsIPrivateDOMEvent> privDOMEvent = do_QueryInterface(aKeyEvent);
+  nsInputEvent* inputEvent =
+    static_cast<nsInputEvent*>(privDOMEvent->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;
 }
--- a/layout/xul/base/src/nsMenuFrame.cpp
+++ b/layout/xul/base/src/nsMenuFrame.cpp
@@ -1095,12 +1095,14 @@
   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) {
@@ -1111,6 +1113,8 @@
       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) {
@@ -1120,6 +1124,10 @@
           accelText += metaText;
           break;
 
+        case nsIDOMKeyEvent::DOM_VK_WIN:
+          accelText += osText;
+          break;
+
         case nsIDOMKeyEvent::DOM_VK_ALT:
           accelText += altText;
           break;
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -1282,13 +1282,13 @@
 
 // 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);
--- a/toolkit/content/tests/chrome/window_keys.xul
+++ b/toolkit/content/tests/chrome/window_keys.xul
@@ -23,6 +23,7 @@
   ["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", { } ],
@@ -30,8 +31,16 @@
   ["", "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 } ],
@@ -148,6 +157,9 @@
   <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)"/>
--- a/toolkit/locales/en-US/chrome/global-platform/mac/platformKeys.properties
+++ b/toolkit/locales/en-US/chrome/global-platform/mac/platformKeys.properties
@@ -12,6 +12,9 @@
 #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
 
--- a/toolkit/locales/en-US/chrome/global-platform/unix/platformKeys.properties
+++ b/toolkit/locales/en-US/chrome/global-platform/unix/platformKeys.properties
@@ -12,6 +12,9 @@
 #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
 
--- a/toolkit/locales/en-US/chrome/global-platform/win/platformKeys.properties
+++ b/toolkit/locales/en-US/chrome/global-platform/win/platformKeys.properties
@@ -12,6 +12,9 @@
 #the command key
 VK_META=Meta
 
+#the win key
+VK_WIN=Win
+
 #the alt key
 VK_ALT=Alt
 
--- a/widget/gtk2/nsGtkKeyUtils.cpp
+++ b/widget/gtk2/nsGtkKeyUtils.cpp
@@ -56,12 +56,8 @@
     { NS_VK_CONTROL,    GDK_Control_R },
     { NS_VK_ALT,        GDK_Alt_L },
     { NS_VK_ALT,        GDK_Alt_R },
-
-    // NS_VK_META is used for Command key of Mac.  It's a modifier key for
-    // shortcut keys like Ctrl key on GTK or Windows.  So, it's really different
-    // from GTK's META key, we shouldn't use it on GTK.
-    // { NS_VK_META,       GDK_Meta_L },
-    // { NS_VK_META,       GDK_Meta_R },
+    { NS_VK_META,       GDK_Meta_L },
+    { NS_VK_META,       GDK_Meta_R },
 
     // Assume that Super or Hyper is always mapped to physical Win key.
     { NS_VK_WIN,        GDK_Super_L },
@@ -378,8 +374,16 @@
 
     // Note that two or more modifiers may use one modifier flag.  E.g.,
     // on Ubuntu 10.10, Alt and Meta share the Mod1 in default settings.
-    //  And also Super and Hyper share the Mod4.
+    // And also Super and Hyper share the Mod4. In such cases, we need to
+    // decide which modifier flag means one of DOM modifiers.
 
+    // mod[0] is Modifier introduced by Mod1.
+    Modifier mod[5];
+    PRInt32 foundLevel[5];
+    for (PRUint32 i = 0; i < ArrayLength(mod); i++) {
+        mod[i] = NOT_MODIFIER;
+        foundLevel[i] = PR_INT32_MAX;
+    }
     const PRUint32 map_size = 8 * xmodmap->max_keypermod;
     for (PRUint32 i = 0; i < map_size; i++) {
         KeyCode keycode = xmodmap->modifiermap[i];
@@ -400,44 +404,85 @@
             xkeymap + (keycode - min_keycode) * keysyms_per_keycode;
         const PRUint32 bit = i / xmodmap->max_keypermod;
         modifierKey->mMask |= 1 << bit;
+
+        // We need to know the meaning of Mod1, Mod2, Mod3, Mod4 and Mod5.
+        // Let's skip if current map is for others.
+        if (bit < 3) {
+            continue;
+        }
+
+        const PRInt32 modIndex = bit - 3;
         for (PRInt32 j = 0; j < keysyms_per_keycode; j++) {
             Modifier modifier = GetModifierForGDKKeyval(syms[j]);
             PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
                 ("KeymapWrapper(%p): InitBySystemSettings, "
-                 "    bit=%d, j=%d, syms[j]=%s(0x%X), modifier=%s",
-                 this, bit, j, gdk_keyval_name(syms[j]), syms[j],
+                 "    Mod%d, j=%d, syms[j]=%s(0x%X), modifier=%s",
+                 this, modIndex + 1, j, gdk_keyval_name(syms[j]), syms[j],
                  GetModifierName(modifier)));
 
-            ModifierIndex index;
             switch (modifier) {
-                case NUM_LOCK:
-                    index = INDEX_NUM_LOCK;
-                    break;
-                case SCROLL_LOCK:
-                    index = INDEX_SCROLL_LOCK;
+                case NOT_MODIFIER:
+                    // Don't overwrite the stored information with
+                    // NOT_MODIFIER.
                     break;
-                case ALT:
-                    index = INDEX_ALT;
-                    break;
-                case SUPER:
-                    index = INDEX_SUPER;
-                    break;
-                case HYPER:
-                    index = INDEX_HYPER;
-                    break;
-                case META:
-                    index = INDEX_META;
-                    break;
-                case ALTGR:
-                    index = INDEX_ALTGR;
+                case CAPS_LOCK:
+                case SHIFT:
+                case CTRL:
+                    // Ignore the modifiers defined in GDK spec. They shouldn't
+                    // be mapped to Mod1-5 because they must not work on native
+                    // GTK applications.
                     break;
                 default:
-                    // NOTE: We always use GDK_SHIFT_MASK, GDK_CONTROL_MASK and
-                    //       GDK_LOCK_MASK for SHIFT, CTRL and CAPS_LOCK.
-                    //       This is standard manners of GTK application.
-                    continue;
+                    // If new modifier is found in higher level than stored
+                    // value, we don't need to overwrite it.
+                    if (j > foundLevel[modIndex]) {
+                        break;
+                    }
+                    // If new modifier is more important than stored value,
+                    // we should overwrite it with new modifier.
+                    if (j == foundLevel[modIndex]) {
+                        mod[modIndex] = NS_MIN(modifier, mod[modIndex]);
+                        break;
+                    }
+                    foundLevel[modIndex] = j;
+                    mod[modIndex] = modifier;
+                    break;
+            }
+        }
+    }
+
+    for (PRUint32 i = 0; i < COUNT_OF_MODIFIER_INDEX; i++) {
+        Modifier modifier;
+        switch (i) {
+            case INDEX_NUM_LOCK:
+                modifier = NUM_LOCK;
+                break;
+            case INDEX_SCROLL_LOCK:
+                modifier = SCROLL_LOCK;
+                break;
+            case INDEX_ALT:
+                modifier = ALT;
+                break;
+            case INDEX_META:
+                modifier = META;
+                break;
+            case INDEX_SUPER:
+                modifier = SUPER;
+                break;
+            case INDEX_HYPER:
+                modifier = HYPER;
+                break;
+            case INDEX_ALTGR:
+                modifier = ALTGR;
+                break;
+            default:
+                MOZ_NOT_REACHED("All indexes must be handled here");
+                break;
+        }
+        for (PRUint32 j = 0; j < ArrayLength(mod); j++) {
+            if (modifier == mod[j]) {
+                mModifierMasks[i] |= 1 << (j + 3);
             }
-            mModifierMasks[index] |= 1 << bit;
         }
     }
 
@@ -534,6 +579,9 @@
     if (keymapWrapper->AreModifiersActive(ALT, aModifierState)) {
         aInputEvent.modifiers |= MODIFIER_ALT;
     }
+    if (keymapWrapper->AreModifiersActive(META, aModifierState)) {
+        aInputEvent.modifiers |= MODIFIER_META;
+    }
     if (keymapWrapper->AreModifiersActive(SUPER, aModifierState) ||
         keymapWrapper->AreModifiersActive(HYPER, aModifierState)) {
         aInputEvent.modifiers |= MODIFIER_OS;
@@ -554,11 +602,13 @@
     PR_LOG(gKeymapWrapperLog, PR_LOG_DEBUG,
         ("KeymapWrapper(%p): InitInputEvent, aModifierState=0x%08X, "
          "aInputEvent.modifiers=0x%04X (Shift: %s, Control: %s, Alt: %s, "
-         "OS: %s, AltGr: %s, CapsLock: %s, NumLock: %s, ScrollLock: %s)",
+         "Meta: %s, OS: %s, AltGr: %s, "
+         "CapsLock: %s, NumLock: %s, ScrollLock: %s)",
          keymapWrapper, aModifierState, aInputEvent.modifiers,
          GetBoolName(aInputEvent.modifiers & MODIFIER_SHIFT),
          GetBoolName(aInputEvent.modifiers & MODIFIER_CONTROL),
          GetBoolName(aInputEvent.modifiers & MODIFIER_ALT),
+         GetBoolName(aInputEvent.modifiers & MODIFIER_META),
          GetBoolName(aInputEvent.modifiers & MODIFIER_OS),
          GetBoolName(aInputEvent.modifiers & MODIFIER_ALTGRAPH),
          GetBoolName(aInputEvent.modifiers & MODIFIER_CAPSLOCK),
@@ -616,7 +666,17 @@
         if (GetModifierForGDKKeyval(keyvalWithoutModifier)) {
             keyval = keyvalWithoutModifier;
         }
-        return GetDOMKeyCodeFromKeyPairs(keyval);
+        // Note that the modifier keycode and activating or deactivating
+        // modifier flag may be mismatched, but it's okay.  If a DOM key
+        // event handler is testing a keydown event, it's more likely being
+        // used to test which key is being pressed than to test which
+        // modifier will become active.  So, if we computed DOM keycode
+        // from modifier flag which were changing by the physical key, then
+        // there would be no other way for the user to generate the original
+        // keycode.
+        PRUint32 DOMKeyCode = GetDOMKeyCodeFromKeyPairs(keyval);
+        NS_ASSERTION(DOMKeyCode, "All modifier keys must have a DOM keycode");
+        return DOMKeyCode;
     }
 
     // If the key isn't printable, let's look at the key pairs.
@@ -1126,9 +1186,11 @@
     // 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",
--- a/widget/gtk2/nsGtkKeyUtils.h
+++ b/widget/gtk2/nsGtkKeyUtils.h
@@ -53,9 +53,9 @@
         SHIFT              = 0x0008,
         CTRL               = 0x0010,
         ALT                = 0x0020,
-        SUPER              = 0x0040,
-        HYPER              = 0x0080,
-        META               = 0x0100,
+        META               = 0x0040,
+        SUPER              = 0x0080,
+        HYPER              = 0x0100,
         ALTGR              = 0x0200
     };
 
@@ -170,9 +170,9 @@
         INDEX_NUM_LOCK,
         INDEX_SCROLL_LOCK,
         INDEX_ALT,
+        INDEX_META,
         INDEX_SUPER,
         INDEX_HYPER,
-        INDEX_META,
         INDEX_ALTGR,
         COUNT_OF_MODIFIER_INDEX
     };
--- a/widget/nsGUIEvent.h
+++ b/widget/nsGUIEvent.h
@@ -1786,6 +1786,17 @@
   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) || \
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -6324,7 +6324,7 @@
   // 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.mIsControlDown || aModKeyState.mIsAltDown)
+      ((aModKeyState.mIsControlDown || aModKeyState.mIsAltDown || aModKeyState.mIsWinDown)
        && !gKbdLayout.IsDeadKey() && KeyboardLayout::IsPrintableCharKey(virtualKeyCode)))
   {
     // Remove a possible WM_CHAR or WM_SYSCHAR messages from the message queue.
@@ -6391,6 +6391,7 @@
     return result;
   }
   else if (!aModKeyState.mIsControlDown && !aModKeyState.mIsAltDown &&
+             !aModKeyState.mIsWinDown &&
              (KeyboardLayout::IsPrintableCharKey(virtualKeyCode) ||
               KeyboardLayout::IsNumpadKey(virtualKeyCode)))
   {

Reply via email to