Пример #1
0
static eEventAction
GetActionForEvent(nsIDOMEvent* aEvent)
{
  WidgetKeyboardEvent* keyEvent =
    aEvent->GetInternalNSEvent()->AsKeyboardEvent();
  if (!keyEvent) {
    return eEventAction_Suppress;
  }

  if (keyEvent->mFlags.mInSystemGroup) {
    NS_ASSERTION(keyEvent->message == NS_KEY_DOWN,
      "Assuming we're listening only keydown event in system group");
    return eEventAction_StopPropagation;
  }

  if (keyEvent->IsAlt() || keyEvent->IsControl() || keyEvent->IsMeta()) {
    // Don't consume keydown event because following keypress event may be
    // handled as access key or shortcut key.
    return (keyEvent->message == NS_KEY_DOWN) ? eEventAction_StopPropagation :
                                                eEventAction_Suppress;
  }

  static const uint32_t kOKKeyCodes[] = {
    nsIDOMKeyEvent::DOM_VK_PAGE_UP, nsIDOMKeyEvent::DOM_VK_PAGE_DOWN,
    nsIDOMKeyEvent::DOM_VK_UP,      nsIDOMKeyEvent::DOM_VK_DOWN, 
    nsIDOMKeyEvent::DOM_VK_HOME,    nsIDOMKeyEvent::DOM_VK_END 
  };

  if (keyEvent->keyCode == nsIDOMKeyEvent::DOM_VK_TAB) {
    return keyEvent->IsShift() ? eEventAction_ShiftTab : eEventAction_Tab;
  }

  if (keyEvent->charCode == ' ' || keyEvent->keyCode == NS_VK_SPACE) {
    return eEventAction_Propagate;
  }

  if (keyEvent->IsShift()) {
    return eEventAction_Suppress;
  }

  for (uint32_t i = 0; i < ArrayLength(kOKKeyCodes); ++i) {
    if (keyEvent->keyCode == kOKKeyCodes[i]) {
      return eEventAction_Propagate;
    }
  }

  return eEventAction_Suppress;
}
Пример #2
0
nsresult
nsMenuFrame::HandleEvent(nsPresContext* aPresContext,
                         WidgetGUIEvent* aEvent,
                         nsEventStatus* aEventStatus)
{
  NS_ENSURE_ARG_POINTER(aEventStatus);
  if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
    return NS_OK;
  }
  nsMenuParent* menuParent = GetMenuParent();
  if (menuParent && menuParent->IsMenuLocked()) {
    return NS_OK;
  }

  nsWeakFrame weakFrame(this);
  if (*aEventStatus == nsEventStatus_eIgnore)
    *aEventStatus = nsEventStatus_eConsumeDoDefault;

  bool onmenu = IsOnMenu();

  if (aEvent->mMessage == eKeyPress && !IsDisabled()) {
    WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
    uint32_t keyCode = keyEvent->keyCode;
#ifdef XP_MACOSX
    // On mac, open menulist on either up/down arrow or space (w/o Cmd pressed)
    if (!IsOpen() && ((keyEvent->charCode == NS_VK_SPACE && !keyEvent->IsMeta()) ||
        (keyCode == NS_VK_UP || keyCode == NS_VK_DOWN))) {
      *aEventStatus = nsEventStatus_eConsumeNoDefault;
      OpenMenu(false);
    }
#else
    // On other platforms, toggle menulist on unmodified F4 or Alt arrow
    if ((keyCode == NS_VK_F4 && !keyEvent->IsAlt()) ||
        ((keyCode == NS_VK_UP || keyCode == NS_VK_DOWN) && keyEvent->IsAlt())) {
      *aEventStatus = nsEventStatus_eConsumeNoDefault;
      ToggleMenuState();
    }
#endif
  }
  else if (aEvent->mMessage == eMouseDown &&
           aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton &&
           !IsDisabled() && IsMenu()) {
    // The menu item was selected. Bring up the menu.
    // We have children.
    // Don't prevent the default action here, since that will also cancel
    // potential drag starts.
    if (!menuParent || menuParent->IsMenuBar()) {
      ToggleMenuState();
    }
    else {
      if (!IsOpen()) {
        menuParent->ChangeMenuItem(this, false, false);
        OpenMenu(false);
      }
    }
  }
  else if (
#ifndef NSCONTEXTMENUISMOUSEUP
           (aEvent->mMessage == eMouseUp &&
            aEvent->AsMouseEvent()->button == WidgetMouseEvent::eRightButton) &&
#else
           aEvent->mMessage == eContextMenu &&
#endif
           onmenu && !IsMenu() && !IsDisabled()) {
    // if this menu is a context menu it accepts right-clicks...fire away!
    // Make sure we cancel default processing of the context menu event so
    // that it doesn't bubble and get seen again by the popuplistener and show
    // another context menu.
    //
    // Furthermore (there's always more, isn't there?), on some platforms (win32
    // being one of them) we get the context menu event on a mouse up while
    // on others we get it on a mouse down. For the ones where we get it on a
    // mouse down, we must continue listening for the right button up event to
    // dismiss the menu.
    if (menuParent->IsContextMenu()) {
      *aEventStatus = nsEventStatus_eConsumeNoDefault;
      Execute(aEvent);
    }
  }
  else if (aEvent->mMessage == eMouseUp &&
           aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton &&
           !IsMenu() && !IsDisabled()) {
    // Execute the execute event handler.
    *aEventStatus = nsEventStatus_eConsumeNoDefault;
    Execute(aEvent);
  }
  else if (aEvent->mMessage == eMouseOut) {
    // Kill our timer if one is active.
    if (mOpenTimer) {
      mOpenTimer->Cancel();
      mOpenTimer = nullptr;
    }

    // Deactivate the menu.
    if (menuParent) {
      bool onmenubar = menuParent->IsMenuBar();
      if (!(onmenubar && menuParent->IsActive())) {
        if (IsMenu() && !onmenubar && IsOpen()) {
          // Submenus don't get closed up immediately.
        }
        else if (this == menuParent->GetCurrentMenuItem()
#ifdef XP_WIN
                 && GetParentMenuListType() == eNotMenuList
#endif
        ) {
          menuParent->ChangeMenuItem(nullptr, false, false);
        }
      }
    }
  }
  else if (aEvent->mMessage == eMouseMove &&
           (onmenu || (menuParent && menuParent->IsMenuBar()))) {
    if (gEatMouseMove) {
      gEatMouseMove = false;
      return NS_OK;
    }

    // Let the menu parent know we're the new item.
    menuParent->ChangeMenuItem(this, false, false);
    NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
    NS_ENSURE_TRUE(menuParent, NS_OK);

    // we need to check if we really became the current menu
    // item or not
    nsMenuFrame *realCurrentItem = menuParent->GetCurrentMenuItem();
    if (realCurrentItem != this) {
      // we didn't (presumably because a context menu was active)
      return NS_OK;
    }

    // Hovering over a menu in a popup should open it without a need for a click.
    // A timer is used so that it doesn't open if the user moves the mouse quickly
    // past the menu. This conditional check ensures that only menus have this
    // behaviour
    if (!IsDisabled() && IsMenu() && !IsOpen() && !mOpenTimer && !menuParent->IsMenuBar()) {
      int32_t menuDelay =
        LookAndFeel::GetInt(LookAndFeel::eIntID_SubmenuDelay, 300); // ms

      // We're a menu, we're built, we're closed, and no timer has been kicked off.
      mOpenTimer = do_CreateInstance("@mozilla.org/timer;1");
      mOpenTimer->InitWithCallback(mTimerMediator, menuDelay, nsITimer::TYPE_ONE_SHOT);
    }
  }
  
  return NS_OK;
}