LCOV - code coverage report
Current view: directory - layout/xul/base/src - nsMenuBarListener.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 182 0 0.0 %
Date: 2012-06-02 Functions: 17 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Communicator client code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Original Author: David W. Hyatt (hyatt@netscape.com)
      24                 :  *   Dean Tessman <dean_tessman@hotmail.com>
      25                 :  *   Mark Hammond <markh@ActiveState.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "nsMenuBarListener.h"
      42                 : #include "nsMenuBarFrame.h"
      43                 : #include "nsMenuPopupFrame.h"
      44                 : #include "nsIDOMNSEvent.h"
      45                 : #include "nsGUIEvent.h"
      46                 : 
      47                 : // Drag & Drop, Clipboard
      48                 : #include "nsIServiceManager.h"
      49                 : #include "nsWidgetsCID.h"
      50                 : #include "nsCOMPtr.h"
      51                 : #include "nsIDOMKeyEvent.h"
      52                 : #include "nsIContent.h"
      53                 : #include "nsIDOMNode.h"
      54                 : #include "nsIDOMElement.h"
      55                 : 
      56                 : #include "nsContentUtils.h"
      57                 : #include "mozilla/Preferences.h"
      58                 : 
      59                 : using namespace mozilla;
      60                 : 
      61                 : /*
      62                 :  * nsMenuBarListener implementation
      63                 :  */
      64                 : 
      65               0 : NS_IMPL_ISUPPORTS1(nsMenuBarListener, nsIDOMEventListener)
      66                 : 
      67                 : #define MODIFIER_SHIFT    1
      68                 : #define MODIFIER_CONTROL  2
      69                 : #define MODIFIER_ALT      4
      70                 : #define MODIFIER_META     8
      71                 : 
      72                 : ////////////////////////////////////////////////////////////////////////
      73                 : 
      74                 : PRInt32 nsMenuBarListener::mAccessKey = -1;
      75                 : PRUint32 nsMenuBarListener::mAccessKeyMask = 0;
      76                 : bool nsMenuBarListener::mAccessKeyFocuses = false;
      77                 : 
      78               0 : nsMenuBarListener::nsMenuBarListener(nsMenuBarFrame* aMenuBar) 
      79               0 :   :mAccessKeyDown(false), mAccessKeyDownCanceled(false)
      80                 : {
      81               0 :   mMenuBarFrame = aMenuBar;
      82               0 : }
      83                 : 
      84                 : ////////////////////////////////////////////////////////////////////////
      85               0 : nsMenuBarListener::~nsMenuBarListener() 
      86                 : {
      87               0 : }
      88                 : 
      89                 : nsresult
      90               0 : nsMenuBarListener::GetMenuAccessKey(PRInt32* aAccessKey)
      91                 : {
      92               0 :   if (!aAccessKey)
      93               0 :     return NS_ERROR_INVALID_POINTER;
      94               0 :   InitAccessKey();
      95               0 :   *aAccessKey = mAccessKey;
      96               0 :   return NS_OK;
      97                 : }
      98                 : 
      99               0 : void nsMenuBarListener::InitAccessKey()
     100                 : {
     101               0 :   if (mAccessKey >= 0)
     102               0 :     return;
     103                 : 
     104                 :   // Compiled-in defaults, in case we can't get LookAndFeel --
     105                 :   // mac doesn't have menu shortcuts, other platforms use alt.
     106                 : #ifdef XP_MACOSX
     107                 :   mAccessKey = 0;
     108                 :   mAccessKeyMask = 0;
     109                 : #else
     110               0 :   mAccessKey = nsIDOMKeyEvent::DOM_VK_ALT;
     111               0 :   mAccessKeyMask = MODIFIER_ALT;
     112                 : #endif
     113                 : 
     114                 :   // Get the menu access key value from prefs, overriding the default:
     115               0 :   mAccessKey = Preferences::GetInt("ui.key.menuAccessKey", mAccessKey);
     116               0 :   if (mAccessKey == nsIDOMKeyEvent::DOM_VK_SHIFT)
     117               0 :     mAccessKeyMask = MODIFIER_SHIFT;
     118               0 :   else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_CONTROL)
     119               0 :     mAccessKeyMask = MODIFIER_CONTROL;
     120               0 :   else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_ALT)
     121               0 :     mAccessKeyMask = MODIFIER_ALT;
     122               0 :   else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_META)
     123               0 :     mAccessKeyMask = MODIFIER_META;
     124                 : 
     125               0 :   mAccessKeyFocuses = Preferences::GetBool("ui.key.menuAccessKeyFocuses");
     126                 : }
     127                 : 
     128                 : void
     129               0 : nsMenuBarListener::ToggleMenuActiveState()
     130                 : {
     131               0 :   nsMenuFrame* closemenu = mMenuBarFrame->ToggleMenuActiveState();
     132               0 :   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     133               0 :   if (pm && closemenu) {
     134               0 :     nsMenuPopupFrame* popupFrame = closemenu->GetPopup();
     135               0 :     if (popupFrame)
     136               0 :       pm->HidePopup(popupFrame->GetContent(), false, false, true);
     137                 :   }
     138               0 : }
     139                 : 
     140                 : ////////////////////////////////////////////////////////////////////////
     141                 : nsresult
     142               0 : nsMenuBarListener::KeyUp(nsIDOMEvent* aKeyEvent)
     143                 : {  
     144               0 :   nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
     145               0 :   if (!keyEvent) {
     146               0 :     return NS_OK;
     147                 :   }
     148                 : 
     149               0 :   InitAccessKey();
     150                 : 
     151                 :   //handlers shouldn't be triggered by non-trusted events.
     152               0 :   nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aKeyEvent);
     153               0 :   bool trustedEvent = false;
     154                 : 
     155               0 :   if (domNSEvent) {
     156               0 :     domNSEvent->GetIsTrusted(&trustedEvent);
     157                 :   }
     158                 : 
     159               0 :   if (!trustedEvent)
     160               0 :     return NS_OK;
     161                 : 
     162               0 :   if (mAccessKey && mAccessKeyFocuses)
     163                 :   {
     164                 :     // On a press of the ALT key by itself, we toggle the menu's 
     165                 :     // active/inactive state.
     166                 :     // Get the ascii key code.
     167                 :     PRUint32 theChar;
     168               0 :     keyEvent->GetKeyCode(&theChar);
     169                 : 
     170               0 :     if (mAccessKeyDown && !mAccessKeyDownCanceled &&
     171                 :         (PRInt32)theChar == mAccessKey)
     172                 :     {
     173                 :       // The access key was down and is now up, and no other
     174                 :       // keys were pressed in between.
     175               0 :       if (!mMenuBarFrame->IsActive()) {
     176               0 :         mMenuBarFrame->SetActiveByKeyboard();
     177                 :       }
     178               0 :       ToggleMenuActiveState();
     179                 :     }
     180               0 :     mAccessKeyDown = false;
     181               0 :     mAccessKeyDownCanceled = false;
     182                 : 
     183               0 :     bool active = mMenuBarFrame->IsActive();
     184               0 :     if (active) {
     185               0 :       aKeyEvent->StopPropagation();
     186               0 :       aKeyEvent->PreventDefault();
     187               0 :       return NS_OK; // I am consuming event
     188                 :     }
     189                 :   }
     190                 :   
     191               0 :   return NS_OK; // means I am NOT consuming event
     192                 : }
     193                 : 
     194                 : ////////////////////////////////////////////////////////////////////////
     195                 : nsresult
     196               0 : nsMenuBarListener::KeyPress(nsIDOMEvent* aKeyEvent)
     197                 : {
     198                 :   // if event has already been handled, bail
     199               0 :   nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aKeyEvent);
     200               0 :   if (domNSEvent) {
     201               0 :     bool eventHandled = false;
     202               0 :     domNSEvent->GetPreventDefault(&eventHandled);
     203               0 :     if (eventHandled) {
     204               0 :       return NS_OK;       // don't consume event
     205                 :     }
     206                 :   }
     207                 : 
     208                 :   //handlers shouldn't be triggered by non-trusted events.
     209               0 :   bool trustedEvent = false;
     210               0 :   if (domNSEvent) {
     211               0 :     domNSEvent->GetIsTrusted(&trustedEvent);
     212                 :   }
     213                 : 
     214               0 :   if (!trustedEvent)
     215               0 :     return NS_OK;
     216                 : 
     217               0 :   nsresult retVal = NS_OK;  // default is to not consume event
     218                 :   
     219               0 :   InitAccessKey();
     220                 : 
     221               0 :   if (mAccessKey)
     222                 :   {
     223                 :     bool preventDefault;
     224               0 :     domNSEvent->GetPreventDefault(&preventDefault);
     225               0 :     if (!preventDefault) {
     226               0 :       nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
     227                 :       PRUint32 keyCode, charCode;
     228               0 :       keyEvent->GetKeyCode(&keyCode);
     229               0 :       keyEvent->GetCharCode(&charCode);
     230                 : 
     231               0 :       bool hasAccessKeyCandidates = charCode != 0;
     232               0 :       if (!hasAccessKeyCandidates) {
     233               0 :         nsEvent* nativeEvent = nsContentUtils::GetNativeEvent(aKeyEvent);
     234               0 :         nsKeyEvent* nativeKeyEvent = static_cast<nsKeyEvent*>(nativeEvent);
     235               0 :         if (nativeKeyEvent) {
     236               0 :           nsAutoTArray<PRUint32, 10> keys;
     237               0 :           nsContentUtils::GetAccessKeyCandidates(nativeKeyEvent, keys);
     238               0 :           hasAccessKeyCandidates = !keys.IsEmpty();
     239                 :         }
     240                 :       }
     241                 : 
     242                 :       // Cancel the access key flag unless we are pressing the access key.
     243               0 :       if (keyCode != (PRUint32)mAccessKey) {
     244               0 :         mAccessKeyDownCanceled = true;
     245                 :       }
     246                 : 
     247               0 :       if (IsAccessKeyPressed(keyEvent) && hasAccessKeyCandidates) {
     248                 :         // Do shortcut navigation.
     249                 :         // A letter was pressed. We want to see if a shortcut gets matched. If
     250                 :         // so, we'll know the menu got activated.
     251               0 :         nsMenuFrame* result = mMenuBarFrame->FindMenuWithShortcut(keyEvent);
     252               0 :         if (result) {
     253               0 :           mMenuBarFrame->SetActiveByKeyboard();
     254               0 :           mMenuBarFrame->SetActive(true);
     255               0 :           result->OpenMenu(true);
     256                 : 
     257                 :           // The opened menu will listen next keyup event.
     258                 :           // Therefore, we should clear the keydown flags here.
     259               0 :           mAccessKeyDown = mAccessKeyDownCanceled = false;
     260                 : 
     261               0 :           aKeyEvent->StopPropagation();
     262               0 :           aKeyEvent->PreventDefault();
     263               0 :           retVal = NS_OK;       // I am consuming event
     264                 :         }
     265                 :       }    
     266                 : #ifndef XP_MACOSX
     267                 :       // Also need to handle F10 specially on Non-Mac platform.
     268               0 :       else if (keyCode == NS_VK_F10) {
     269               0 :         if ((GetModifiers(keyEvent) & ~MODIFIER_CONTROL) == 0) {
     270                 :           // The F10 key just went down by itself or with ctrl pressed.
     271                 :           // In Windows, both of these activate the menu bar.
     272               0 :           mMenuBarFrame->SetActiveByKeyboard();
     273               0 :           ToggleMenuActiveState();
     274                 : 
     275               0 :           aKeyEvent->StopPropagation();
     276               0 :           aKeyEvent->PreventDefault();
     277               0 :           return NS_OK; // consume the event
     278                 :         }
     279                 :       }
     280                 : #endif // !XP_MACOSX
     281                 :     } 
     282                 :   }
     283                 : 
     284               0 :   return retVal;
     285                 : }
     286                 : 
     287                 : bool
     288               0 : nsMenuBarListener::IsAccessKeyPressed(nsIDOMKeyEvent* aKeyEvent)
     289                 : {
     290               0 :   InitAccessKey();
     291                 :   // No other modifiers are allowed to be down except for Shift.
     292               0 :   PRUint32 modifiers = GetModifiers(aKeyEvent);
     293                 : 
     294                 :   return (mAccessKeyMask != MODIFIER_SHIFT &&
     295                 :           (modifiers & mAccessKeyMask) &&
     296               0 :           (modifiers & ~(mAccessKeyMask | MODIFIER_SHIFT)) == 0);
     297                 : }
     298                 : 
     299                 : PRUint32
     300               0 : nsMenuBarListener::GetModifiers(nsIDOMKeyEvent* aKeyEvent)
     301                 : {
     302               0 :   PRUint32 modifiers = 0;
     303                 :   bool modifier;
     304                 : 
     305               0 :   aKeyEvent->GetShiftKey(&modifier);
     306               0 :   if (modifier)
     307               0 :     modifiers |= MODIFIER_SHIFT;
     308                 : 
     309               0 :   aKeyEvent->GetCtrlKey(&modifier);
     310               0 :   if (modifier)
     311               0 :     modifiers |= MODIFIER_CONTROL;
     312                 : 
     313               0 :   aKeyEvent->GetAltKey(&modifier);
     314               0 :   if (modifier)
     315               0 :     modifiers |= MODIFIER_ALT;
     316                 : 
     317               0 :   aKeyEvent->GetMetaKey(&modifier);
     318               0 :   if (modifier)
     319               0 :     modifiers |= MODIFIER_META;
     320                 : 
     321               0 :   return modifiers;
     322                 : }
     323                 : 
     324                 : ////////////////////////////////////////////////////////////////////////
     325                 : nsresult
     326               0 : nsMenuBarListener::KeyDown(nsIDOMEvent* aKeyEvent)
     327                 : {
     328               0 :   InitAccessKey();
     329                 : 
     330                 :   //handlers shouldn't be triggered by non-trusted events.
     331               0 :   nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aKeyEvent);
     332               0 :   bool trustedEvent = false;
     333                 : 
     334               0 :   if (domNSEvent) {
     335               0 :     domNSEvent->GetIsTrusted(&trustedEvent);
     336                 :   }
     337                 : 
     338               0 :   if (!trustedEvent)
     339               0 :     return NS_OK;
     340                 : 
     341               0 :   if (mAccessKey && mAccessKeyFocuses)
     342                 :   {
     343               0 :     nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
     344                 :     PRUint32 theChar;
     345               0 :     keyEvent->GetKeyCode(&theChar);
     346                 : 
     347                 :     // No other modifiers can be down.
     348                 :     // Especially CTRL.  CTRL+ALT == AltGR, and we'll fuck up on non-US
     349                 :     // enhanced 102-key keyboards if we don't check this.
     350                 :     bool isAccessKeyDownEvent =
     351                 :       ((theChar == (PRUint32)mAccessKey) &&
     352               0 :        (GetModifiers(keyEvent) & ~mAccessKeyMask) == 0);
     353                 : 
     354               0 :     if (!mAccessKeyDown) {
     355                 :       // If accesskey isn't being pressed and the key isn't the accesskey,
     356                 :       // ignore the event.
     357               0 :       if (!isAccessKeyDownEvent) {
     358               0 :         return NS_OK;
     359                 :       }
     360                 : 
     361                 :       // Otherwise, accept the accesskey state.
     362               0 :       mAccessKeyDown = true;
     363               0 :       mAccessKeyDownCanceled = false;
     364               0 :       return NS_OK;
     365                 :     }
     366                 : 
     367                 :     // If the pressed accesskey was canceled already, ignore the event.
     368               0 :     if (mAccessKeyDownCanceled) {
     369               0 :       return NS_OK;
     370                 :     }
     371                 : 
     372                 :     // Some key other than the access key just went down,
     373                 :     // so we won't activate the menu bar when the access key is released.
     374               0 :     mAccessKeyDownCanceled = !isAccessKeyDownEvent;
     375                 :   }
     376                 : 
     377               0 :   return NS_OK; // means I am NOT consuming event
     378                 : }
     379                 : 
     380                 : ////////////////////////////////////////////////////////////////////////
     381                 : 
     382                 : nsresult
     383               0 : nsMenuBarListener::Blur(nsIDOMEvent* aEvent)
     384                 : {
     385               0 :   if (!mMenuBarFrame->IsMenuOpen() && mMenuBarFrame->IsActive()) {
     386               0 :     ToggleMenuActiveState();
     387                 :   }
     388                 :   // Reset the accesskey state because we cannot receive the keyup event for
     389                 :   // the pressing accesskey.
     390               0 :   mAccessKeyDown = false;
     391               0 :   mAccessKeyDownCanceled = false;
     392               0 :   return NS_OK; // means I am NOT consuming event
     393                 : }
     394                 :   
     395                 : ////////////////////////////////////////////////////////////////////////
     396                 : nsresult 
     397               0 : nsMenuBarListener::MouseDown(nsIDOMEvent* aMouseEvent)
     398                 : {
     399                 :   // NOTE: MouseDown method listens all phases
     400                 : 
     401                 :   // Even if the mousedown event is canceled, it means the user don't want
     402                 :   // to activate the menu.  Therefore, we need to record it at capturing (or
     403                 :   // target) phase.
     404               0 :   if (mAccessKeyDown) {
     405               0 :     mAccessKeyDownCanceled = true;
     406                 :   }
     407                 : 
     408               0 :   PRUint16 phase = 0;
     409               0 :   nsresult rv = aMouseEvent->GetEventPhase(&phase);
     410               0 :   NS_ENSURE_SUCCESS(rv, rv);
     411                 :   // Don't do anything at capturing phase, any behavior should be cancelable.
     412               0 :   if (phase == nsIDOMEvent::CAPTURING_PHASE) {
     413               0 :     return NS_OK;
     414                 :   }
     415                 : 
     416               0 :   if (!mMenuBarFrame->IsMenuOpen() && mMenuBarFrame->IsActive())
     417               0 :     ToggleMenuActiveState();
     418                 : 
     419               0 :   return NS_OK; // means I am NOT consuming event
     420                 : }
     421                 : 
     422                 : ////////////////////////////////////////////////////////////////////////
     423                 : nsresult
     424               0 : nsMenuBarListener::HandleEvent(nsIDOMEvent* aEvent)
     425                 : {
     426               0 :   nsAutoString eventType;
     427               0 :   aEvent->GetType(eventType);
     428                 :   
     429               0 :   if (eventType.EqualsLiteral("keyup")) {
     430               0 :     return KeyUp(aEvent);
     431                 :   }
     432               0 :   if (eventType.EqualsLiteral("keydown")) {
     433               0 :     return KeyDown(aEvent);
     434                 :   }
     435               0 :   if (eventType.EqualsLiteral("keypress")) {
     436               0 :     return KeyPress(aEvent);
     437                 :   }
     438               0 :   if (eventType.EqualsLiteral("blur")) {
     439               0 :     return Blur(aEvent);
     440                 :   }
     441               0 :   if (eventType.EqualsLiteral("mousedown")) {
     442               0 :     return MouseDown(aEvent);
     443                 :   }
     444                 : 
     445               0 :   NS_ABORT();
     446                 : 
     447               0 :   return NS_OK;
     448                 : }

Generated by: LCOV version 1.7