void
nsXBLWindowKeyHandler::HandleEventOnCaptureInDefaultEventGroup(
                         nsIDOMKeyEvent* aEvent)
{
  WidgetKeyboardEvent* widgetKeyboardEvent =
    aEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();

  if (widgetKeyboardEvent->mFlags.mOnlySystemGroupDispatchInContent) {
    MOZ_RELEASE_ASSERT(
      widgetKeyboardEvent->mFlags.mNoCrossProcessBoundaryForwarding);
    return;
  }

  bool isReserved = false;
  if (HasHandlerForEvent(aEvent, &isReserved) && isReserved) {
    // For reserved commands (such as Open New Tab), we don't to wait for
    // the content to answer (so mWantReplyFromContentProcess remains false),
    // neither to give a chance for content to override its behavior.
    widgetKeyboardEvent->StopCrossProcessForwarding();
    // If the key combination is reserved by chrome, we shouldn't expose the
    // keyboard event to web contents because such keyboard events shouldn't be
    // cancelable.  So, it's not good behavior to fire keyboard events but
    // to ignore the defaultPrevented attribute value in chrome.
    widgetKeyboardEvent->mFlags.mOnlySystemGroupDispatchInContent = true;
  }
}
void KeyboardEvent::GetInitDict(KeyboardEventInit& aParam)
{
  GetKey(aParam.mKey);
  GetCode(aParam.mCode);
  aParam.mLocation = Location();
  aParam.mRepeat = Repeat();
  aParam.mIsComposing = IsComposing();

  // legacy attributes
  aParam.mKeyCode = KeyCode();
  aParam.mCharCode = CharCode();
  aParam.mWhich = Which();

  // modifiers from EventModifierInit
  aParam.mCtrlKey = CtrlKey();
  aParam.mShiftKey = ShiftKey();
  aParam.mAltKey = AltKey();
  aParam.mMetaKey = MetaKey();

  WidgetKeyboardEvent* internalEvent = mEvent->AsKeyboardEvent();
  aParam.mModifierAltGraph = internalEvent->IsAltGraph();
  aParam.mModifierCapsLock = internalEvent->IsCapsLocked();
  aParam.mModifierFn = internalEvent->IsFn();
  aParam.mModifierFnLock = internalEvent->IsFnLocked();
  aParam.mModifierNumLock = internalEvent->IsNumLocked();
  aParam.mModifierOS = internalEvent->IsOS();
  aParam.mModifierScrollLock = internalEvent->IsScrollLocked();
  aParam.mModifierSymbol = internalEvent->IsSymbol();
  aParam.mModifierSymbolLock = internalEvent->IsSymbolLocked();

  // EventInit
  aParam.mBubbles =  internalEvent->mFlags.mBubbles;
  aParam.mCancelable = internalEvent->mFlags.mCancelable;
}
NS_IMETHODIMP
ChromeTooltipListener::HandleEvent(nsIDOMEvent* aEvent)
{
  nsAutoString eventType;
  aEvent->GetType(eventType);

  if (eventType.EqualsLiteral("mousedown")) {
    return HideTooltip();
  } else if (eventType.EqualsLiteral("keydown")) {
    WidgetKeyboardEvent* keyEvent = aEvent->WidgetEventPtr()->AsKeyboardEvent();
    if (!keyEvent->IsModifierKeyEvent()) {
      return HideTooltip();
    }

    return NS_OK;
  } else if (eventType.EqualsLiteral("mouseout")) {
    // Reset flag so that tooltip will display on the next MouseMove
    mTooltipShownOnce = false;
    return HideTooltip();
  } else if (eventType.EqualsLiteral("mousemove")) {
    return MouseMove(aEvent);
  }

  NS_ERROR("Unexpected event type");
  return NS_OK;
}
//
// WalkHandlersInternal and WalkHandlersAndExecute
//
// Given a particular DOM event and a pointer to the first handler in the list,
// scan through the list to find something to handle the event. If aExecute = true,
// the handler will be executed; otherwise just return an answer telling if a handler
// for that event was found.
//
bool
nsXBLWindowKeyHandler::WalkHandlersInternal(nsIDOMKeyEvent* aKeyEvent,
                                            nsIAtom* aEventType, 
                                            nsXBLPrototypeHandler* aHandler,
                                            bool aExecute,
                                            bool* aOutReservedForChrome)
{
  WidgetKeyboardEvent* nativeKeyboardEvent =
    aKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
  MOZ_ASSERT(nativeKeyboardEvent);

  AutoShortcutKeyCandidateArray shortcutKeys;
  nativeKeyboardEvent->GetShortcutKeyCandidates(shortcutKeys);

  if (shortcutKeys.IsEmpty()) {
    return WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler,
                                  0, IgnoreModifierState(),
                                  aExecute, aOutReservedForChrome);
  }

  for (uint32_t i = 0; i < shortcutKeys.Length(); ++i) {
    ShortcutKeyCandidate& key = shortcutKeys[i];
    IgnoreModifierState ignoreModifierState;
    ignoreModifierState.mShift = key.mIgnoreShift;
    if (WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler,
                               key.mCharCode, ignoreModifierState,
                               aExecute, aOutReservedForChrome)) {
      return true;
    }
  }
  return false;
}
Exemple #5
0
// defined in nsWindowBase, called from shared module KeyboardLayout.
bool
MetroWidget::DispatchKeyboardEvent(WidgetKeyboardEvent* aEvent)
{
  MOZ_ASSERT(aEvent);
  WidgetKeyboardEvent* keyEvent =
    new WidgetKeyboardEvent(aEvent->mFlags.mIsTrusted,
                            aEvent->message, aEvent->widget);
  // XXX note this leaves pluginEvent null, which is fine for now.
  keyEvent->AssignKeyEventData(*aEvent, true);
  mKeyEventQueue.Push(keyEvent);
  nsCOMPtr<nsIRunnable> runnable =
    NS_NewRunnableMethod(this, &MetroWidget::DeliverNextKeyboardEvent);
  NS_DispatchToCurrentThread(runnable);
  return false;
}
NS_IMETHODIMP
nsDOMKeyboardEvent::InitKeyEvent(const nsAString& aType, bool aCanBubble, bool aCancelable,
                                 nsIDOMWindow* aView, bool aCtrlKey, bool aAltKey,
                                 bool aShiftKey, bool aMetaKey,
                                 uint32_t aKeyCode, uint32_t aCharCode)
{
  nsresult rv = nsDOMUIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, 0);
  NS_ENSURE_SUCCESS(rv, rv);

  WidgetKeyboardEvent* keyEvent = mEvent->AsKeyboardEvent();
  keyEvent->InitBasicModifiers(aCtrlKey, aAltKey, aShiftKey, aMetaKey);
  keyEvent->keyCode = aKeyCode;
  keyEvent->charCode = aCharCode;

  return NS_OK;
}
Exemple #7
0
void
KeyboardEvent::InitKeyEvent(const nsAString& aType, bool aCanBubble,
                            bool aCancelable, nsGlobalWindowInner* aView,
                            bool aCtrlKey, bool aAltKey,
                            bool aShiftKey, bool aMetaKey,
                            uint32_t aKeyCode, uint32_t aCharCode)
{
  NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);

  UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, 0);

  WidgetKeyboardEvent* keyEvent = mEvent->AsKeyboardEvent();
  keyEvent->InitBasicModifiers(aCtrlKey, aAltKey, aShiftKey, aMetaKey);
  keyEvent->mKeyCode = aKeyCode;
  keyEvent->mCharCode = aCharCode;
}
bool
NativeKeyBindings::Execute(const WidgetKeyboardEvent& aEvent,
                           DoCommandCallback aCallback,
                           void* aCallbackData)
{
  // If the native key event is set, it must be synthesized for tests.
  // We just ignore such events because this behavior depends on system
  // settings.
  if (!aEvent.mNativeKeyEvent) {
    // It must be synthesized event or dispatched DOM event from chrome.
    return false;
  }

  guint keyval;

  if (aEvent.mCharCode) {
    keyval = gdk_unicode_to_keyval(aEvent.mCharCode);
  } else {
    keyval =
      static_cast<GdkEventKey*>(aEvent.mNativeKeyEvent)->keyval;
  }

  if (ExecuteInternal(aEvent, aCallback, aCallbackData, keyval)) {
    return true;
  }

  for (uint32_t i = 0; i < aEvent.mAlternativeCharCodes.Length(); ++i) {
    uint32_t ch = aEvent.IsShift() ?
      aEvent.mAlternativeCharCodes[i].mShiftedCharCode :
      aEvent.mAlternativeCharCodes[i].mUnshiftedCharCode;
    if (ch && ch != aEvent.mCharCode) {
      keyval = gdk_unicode_to_keyval(ch);
      if (ExecuteInternal(aEvent, aCallback, aCallbackData, keyval)) {
        return true;
      }
    }
  }

/*
gtk_bindings_activate_event is preferable, but it has unresolved bug:
http://bugzilla.gnome.org/show_bug.cgi?id=162726
The bug was already marked as FIXED.  However, somebody reports that the
bug still exists.
Also gtk_bindings_activate may work with some non-shortcuts operations
(todo: check it). See bug 411005 and bug 406407.

Code, which should be used after fixing GNOME bug 162726:

  gtk_bindings_activate_event(GTK_OBJECT(mNativeTarget),
    static_cast<GdkEventKey*>(aEvent.mNativeKeyEvent));
*/

  return false;
}
nsresult
TextInputProcessor::PrepareKeyboardEventToDispatch(
                      WidgetKeyboardEvent& aKeyboardEvent,
                      uint32_t aKeyFlags)
{
  if (NS_WARN_IF(aKeyboardEvent.mCodeNameIndex == CODE_NAME_INDEX_USE_STRING)) {
    return NS_ERROR_INVALID_ARG;
  }
  if ((aKeyFlags & KEY_NON_PRINTABLE_KEY) &&
      NS_WARN_IF(aKeyboardEvent.mKeyNameIndex == KEY_NAME_INDEX_USE_STRING)) {
    return NS_ERROR_INVALID_ARG;
  }
  if ((aKeyFlags & KEY_FORCE_PRINTABLE_KEY) &&
      aKeyboardEvent.mKeyNameIndex != KEY_NAME_INDEX_USE_STRING) {
    aKeyboardEvent.GetDOMKeyName(aKeyboardEvent.mKeyValue);
    aKeyboardEvent.mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
  }
  if (aKeyFlags & KEY_KEEP_KEY_LOCATION_STANDARD) {
    // If .location is initialized with specific value, using
    // KEY_KEEP_KEY_LOCATION_STANDARD must be a bug of the caller.
    // Let's throw an exception for notifying the developer of this bug.
    if (NS_WARN_IF(aKeyboardEvent.mLocation)) {
      return NS_ERROR_INVALID_ARG;
    }
  } else if (!aKeyboardEvent.mLocation) {
    // If KeyboardEvent.mLocation is 0, it may be uninitialized.  If so, we
    // should compute proper mLocation value from its .code value.
    aKeyboardEvent.mLocation =
      WidgetKeyboardEvent::ComputeLocationFromCodeValue(
        aKeyboardEvent.mCodeNameIndex);
  }

  if (aKeyFlags & KEY_KEEP_KEYCODE_ZERO) {
    // If .keyCode is initialized with specific value, using
    // KEY_KEEP_KEYCODE_ZERO must be a bug of the caller.  Let's throw an
    // exception for notifying the developer of such bug.
    if (NS_WARN_IF(aKeyboardEvent.mKeyCode)) {
      return NS_ERROR_INVALID_ARG;
    }
  } else if (!aKeyboardEvent.mKeyCode &&
             aKeyboardEvent.mKeyNameIndex > KEY_NAME_INDEX_Unidentified &&
             aKeyboardEvent.mKeyNameIndex < KEY_NAME_INDEX_USE_STRING) {
    // If KeyboardEvent.keyCode is 0, it may be uninitialized.  If so, we may
    // be able to decide a good .keyCode value if the .key value is a
    // non-printable key.
    aKeyboardEvent.mKeyCode =
      WidgetKeyboardEvent::ComputeKeyCodeFromKeyNameIndex(
        aKeyboardEvent.mKeyNameIndex);
  }

  aKeyboardEvent.mIsSynthesizedByTIP = (mForTests)? false : true;

  return NS_OK;
}
NS_IMETHODIMP
KeyboardEvent::InitKeyEvent(const nsAString& aType,
                            bool aCanBubble,
                            bool aCancelable,
                            mozIDOMWindow* aView,
                            bool aCtrlKey,
                            bool aAltKey,
                            bool aShiftKey,
                            bool aMetaKey,
                            uint32_t aKeyCode,
                            uint32_t aCharCode)
{
    UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, 0);

    WidgetKeyboardEvent* keyEvent = mEvent->AsKeyboardEvent();
    keyEvent->InitBasicModifiers(aCtrlKey, aAltKey, aShiftKey, aMetaKey);
    keyEvent->mKeyCode = aKeyCode;
    keyEvent->mCharCode = aCharCode;

    return NS_OK;
}
Exemple #11
0
void
KeyboardEvent::InitKeyboardEvent(const nsAString& aType,
                                 bool aCanBubble,
                                 bool aCancelable,
                                 nsGlobalWindowInner* aView,
                                 const nsAString& aKey,
                                 uint32_t aLocation,
                                 bool aCtrlKey,
                                 bool aAltKey,
                                 bool aShiftKey,
                                 bool aMetaKey,
                                 ErrorResult& aRv)
{
  NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);

  UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, 0);

  WidgetKeyboardEvent* keyEvent = mEvent->AsKeyboardEvent();
  keyEvent->InitBasicModifiers(aCtrlKey, aAltKey, aShiftKey, aMetaKey);
  keyEvent->mLocation = aLocation;
  keyEvent->mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
  keyEvent->mKeyValue = aKey;
}
Exemple #12
0
bool
nsXBLKeyEventHandler::ExecuteMatchedHandlers(
                        nsIDOMKeyEvent* aKeyEvent,
                        uint32_t aCharCode,
                        const IgnoreModifierState& aIgnoreModifierState)
{
  WidgetEvent* event = aKeyEvent->GetInternalNSEvent();
  nsCOMPtr<EventTarget> target = aKeyEvent->InternalDOMEvent()->GetCurrentTarget();

  bool executed = false;
  for (uint32_t i = 0; i < mProtoHandlers.Length(); ++i) {
    nsXBLPrototypeHandler* handler = mProtoHandlers[i];
    bool hasAllowUntrustedAttr = handler->HasAllowUntrustedAttr();
    if ((event->mFlags.mIsTrusted ||
        (hasAllowUntrustedAttr && handler->AllowUntrustedEvents()) ||
        (!hasAllowUntrustedAttr && !mIsBoundToChrome && !mUsingContentXBLScope)) &&
        handler->KeyEventMatched(aKeyEvent, aCharCode, aIgnoreModifierState)) {
      handler->ExecuteHandler(target, aKeyEvent);
      executed = true;
    }
  }
#ifdef XP_WIN
  // Windows native applications ignore Windows-Logo key state when checking
  // shortcut keys even if the key is pressed.  Therefore, if there is no
  // shortcut key which exactly matches current modifier state, we should
  // retry to look for a shortcut key without the Windows-Logo key press.
  if (!executed && !aIgnoreModifierState.mOS) {
    WidgetKeyboardEvent* keyEvent = event->AsKeyboardEvent();
    if (keyEvent && keyEvent->IsOS()) {
      IgnoreModifierState ignoreModifierState(aIgnoreModifierState);
      ignoreModifierState.mOS = true;
      return ExecuteMatchedHandlers(aKeyEvent, aCharCode, ignoreModifierState);
    }
  }
#endif
  return executed;
}
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;
}
bool
TextEventDispatcher::DispatchKeyboardEventInternal(
                       uint32_t aMessage,
                       const WidgetKeyboardEvent& aKeyboardEvent,
                       nsEventStatus& aStatus,
                       uint32_t aIndexOfKeypress)
{
  MOZ_ASSERT(aMessage == NS_KEY_DOWN || aMessage == NS_KEY_UP ||
             aMessage == NS_KEY_PRESS, "Invalid aMessage value");
  nsresult rv = GetState();
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return false;
  }

  // If the key shouldn't cause keypress events, don't this patch them.
  if (aMessage == NS_KEY_PRESS && !aKeyboardEvent.ShouldCauseKeypressEvents()) {
    return false;
  }

  // Basically, key events shouldn't be dispatched during composition.
  if (IsComposing()) {
    // However, if we need to behave like other browsers, we need the keydown
    // and keyup events.  Note that this behavior is also allowed by D3E spec.
    // FYI: keypress events must not be fired during composition.
    if (!sDispatchKeyEventsDuringComposition || aMessage == NS_KEY_PRESS) {
      return false;
    }
    // XXX If there was mOnlyContentDispatch for this case, it might be useful
    //     because our chrome doesn't assume that key events are fired during
    //     composition.
  }

  WidgetKeyboardEvent keyEvent(true, aMessage, mWidget);
  InitEvent(keyEvent);
  keyEvent.AssignKeyEventData(aKeyboardEvent, false);

  if (aStatus == nsEventStatus_eConsumeNoDefault) {
    // If the key event should be dispatched as consumed event, marking it here.
    // This is useful to prevent double action.  E.g., when the key was already
    // handled by system, our chrome shouldn't handle it.
    keyEvent.mFlags.mDefaultPrevented = true;
  }

  // Corrects each member for the specific key event type.
  if (aMessage == NS_KEY_DOWN || aMessage == NS_KEY_UP) {
    MOZ_ASSERT(!aIndexOfKeypress,
      "aIndexOfKeypress must be 0 for either NS_KEY_DOWN or NS_KEY_UP");
    // charCode of keydown and keyup should be 0.
    keyEvent.charCode = 0;
  } else if (keyEvent.mKeyNameIndex != KEY_NAME_INDEX_USE_STRING) {
    MOZ_ASSERT(!aIndexOfKeypress,
      "aIndexOfKeypress must be 0 for NS_KEY_PRESS of non-printable key");
    // If keypress event isn't caused by printable key, its charCode should
    // be 0.
    keyEvent.charCode = 0;
  } else {
    MOZ_RELEASE_ASSERT(
      !aIndexOfKeypress || aIndexOfKeypress < keyEvent.mKeyValue.Length(),
      "aIndexOfKeypress must be 0 - mKeyValue.Length() - 1");
    keyEvent.keyCode = 0;
    wchar_t ch =
      keyEvent.mKeyValue.IsEmpty() ? 0 : keyEvent.mKeyValue[aIndexOfKeypress];
    keyEvent.charCode = static_cast<uint32_t>(ch);
    if (ch) {
      keyEvent.mKeyValue.Assign(ch);
    } else {
      keyEvent.mKeyValue.Truncate();
    }
  }
  if (aMessage == NS_KEY_UP) {
    // mIsRepeat of keyup event must be false.
    keyEvent.mIsRepeat = false;
  }
  // mIsComposing should be initialized later.
  keyEvent.mIsComposing = false;
  // XXX Currently, we don't support to dispatch key event with native key
  //     event information.
  keyEvent.mNativeKeyEvent = nullptr;
  // XXX Currently, we don't support to dispatch key events with data for
  // plugins.
  keyEvent.mPluginEvent.Clear();
  // TODO: Manage mUniqueId here.

  DispatchEvent(mWidget, keyEvent, aStatus);
  return true;
}
bool
nsXBLWindowKeyHandler::WalkHandlersAndExecute(
                         nsIDOMKeyEvent* aKeyEvent,
                         nsIAtom* aEventType,
                         nsXBLPrototypeHandler* aFirstHandler,
                         uint32_t aCharCode,
                         const IgnoreModifierState& aIgnoreModifierState,
                         bool aExecute,
                         bool* aOutReservedForChrome)
{
  // Try all of the handlers until we find one that matches the event.
  for (nsXBLPrototypeHandler* handler = aFirstHandler;
       handler;
       handler = handler->GetNextHandler()) {
    bool stopped = aKeyEvent->AsEvent()->IsDispatchStopped();
    if (stopped) {
      // The event is finished, don't execute any more handlers
      return false;
    }

    if (aExecute) {
      // If it's executing matched handlers, the event type should exactly be
      // matched.
      if (!handler->EventTypeEquals(aEventType)) {
        continue;
      }
    } else {
      if (handler->EventTypeEquals(nsGkAtoms::keypress)) {
        // If the handler is a keypress event handler, we also need to check
        // if coming keydown event is a preceding event of reserved key
        // combination because if default action of a keydown event is
        // prevented, following keypress event won't be fired.  However, if
        // following keypress event is reserved, we shouldn't allow web
        // contents to prevent the default of the preceding keydown event.
        if (aEventType != nsGkAtoms::keydown &&
            aEventType != nsGkAtoms::keypress) {
          continue;
        }
      } else if (!handler->EventTypeEquals(aEventType)) {
        // Otherwise, aEventType should exactly be matched.
        continue;
      }
    }

    // Check if the keyboard event *may* execute the handler.
    if (!handler->KeyEventMatched(aKeyEvent, aCharCode, aIgnoreModifierState)) {
      continue;  // try the next one
    }

    // Before executing this handler, check that it's not disabled,
    // and that it has something to do (oncommand of the <key> or its
    // <command> is non-empty).
    nsCOMPtr<Element> commandElement;
    if (!GetElementForHandler(handler, getter_AddRefs(commandElement))) {
      continue;
    }

    bool isReserved = false;
    if (commandElement) {
      if (!IsExecutableElement(commandElement)) {
        continue;
      }

      isReserved =
        commandElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::reserved,
                                    nsGkAtoms::_true, eCaseMatters);
      if (aOutReservedForChrome) {
        *aOutReservedForChrome = isReserved;
      }
    }

    if (!aExecute) {
      if (handler->EventTypeEquals(aEventType)) {
        return true;
      }
      // If the command is reserved and the event is keydown, check also if
      // the handler is for keypress because if following keypress event is
      // reserved, we shouldn't dispatch the event into web contents.
      if (isReserved &&
          aEventType == nsGkAtoms::keydown &&
          handler->EventTypeEquals(nsGkAtoms::keypress)) {
        return true;
      }
      // Otherwise, we've not found a handler for the event yet.
      continue;
    }

    nsCOMPtr<EventTarget> target;
    nsCOMPtr<Element> chromeHandlerElement = GetElement();
    if (chromeHandlerElement) {
      // XXX commandElement may be nullptr...
      target = commandElement;
    } else {
      target = mTarget;
    }

    // XXX Do we execute only one handler even if the handler neither stops
    //     propagation nor prevents default of the event?
    nsresult rv = handler->ExecuteHandler(target, aKeyEvent->AsEvent());
    if (NS_SUCCEEDED(rv)) {
      return true;
    }
  }

#ifdef XP_WIN
  // Windows native applications ignore Windows-Logo key state when checking
  // shortcut keys even if the key is pressed.  Therefore, if there is no
  // shortcut key which exactly matches current modifier state, we should
  // retry to look for a shortcut key without the Windows-Logo key press.
  if (!aIgnoreModifierState.mOS) {
    WidgetKeyboardEvent* keyEvent =
      aKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
    if (keyEvent && keyEvent->IsOS()) {
      IgnoreModifierState ignoreModifierState(aIgnoreModifierState);
      ignoreModifierState.mOS = true;
      return WalkHandlersAndExecute(aKeyEvent, aEventType, aFirstHandler,
                                    aCharCode, ignoreModifierState, aExecute);
    }
  }
#endif

  return false;
}
Exemple #16
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;
}
bool
nsXBLWindowKeyHandler::WalkHandlersAndExecute(
                         nsIDOMKeyEvent* aKeyEvent,
                         nsIAtom* aEventType,
                         nsXBLPrototypeHandler* aHandler,
                         uint32_t aCharCode,
                         const IgnoreModifierState& aIgnoreModifierState,
                         bool aExecute,
                         bool* aOutReservedForChrome)
{
  nsresult rv;

  // Try all of the handlers until we find one that matches the event.
  for (nsXBLPrototypeHandler *currHandler = aHandler; currHandler;
       currHandler = currHandler->GetNextHandler()) {
    bool stopped = aKeyEvent->AsEvent()->IsDispatchStopped();
    if (stopped) {
      // The event is finished, don't execute any more handlers
      return false;
    }

    if (!EventMatched(currHandler, aEventType, aKeyEvent,
                      aCharCode, aIgnoreModifierState)) {
      continue;  // try the next one
    }

    // Before executing this handler, check that it's not disabled,
    // and that it has something to do (oncommand of the <key> or its
    // <command> is non-empty).
    nsCOMPtr<nsIContent> elt = currHandler->GetHandlerElement();
    nsCOMPtr<Element> commandElt;

    // See if we're in a XUL doc.
    nsCOMPtr<Element> el = GetElement();
    if (el && elt) {
      // We are.  Obtain our command attribute.
      nsAutoString command;
      elt->GetAttr(kNameSpaceID_None, nsGkAtoms::command, command);
      if (!command.IsEmpty()) {
        // Locate the command element in question.  Note that we
        // know "elt" is in a doc if we're dealing with it here.
        NS_ASSERTION(elt->IsInDoc(), "elt must be in document");
        nsIDocument *doc = elt->GetCurrentDoc();
        if (doc)
          commandElt = do_QueryInterface(doc->GetElementById(command));

        if (!commandElt) {
          NS_ERROR("A XUL <key> is observing a command that doesn't exist. Unable to execute key binding!");
          continue;
        }
      }
    }

    if (!commandElt) {
      commandElt = do_QueryInterface(elt);
    }

    if (commandElt) {
      nsAutoString value;
      commandElt->GetAttribute(NS_LITERAL_STRING("disabled"), value);
      if (value.EqualsLiteral("true")) {
        continue;  // this handler is disabled, try the next one
      }

      // Check that there is an oncommand handler
      commandElt->GetAttribute(NS_LITERAL_STRING("oncommand"), value);
      if (value.IsEmpty()) {
        continue;  // nothing to do
      }

      if (aOutReservedForChrome) {
        // The caller wants to know if this is a reserved command
        commandElt->GetAttribute(NS_LITERAL_STRING("reserved"), value);
        *aOutReservedForChrome = value.EqualsLiteral("true");
      }
    }

    nsCOMPtr<EventTarget> piTarget;
    nsCOMPtr<Element> element = GetElement();
    if (element) {
      piTarget = commandElt;
    } else {
      piTarget = mTarget;
    }

    if (!aExecute) {
      return true;
    }

    rv = currHandler->ExecuteHandler(piTarget, aKeyEvent->AsEvent());
    if (NS_SUCCEEDED(rv)) {
      return true;
    }
  }

#ifdef XP_WIN
  // Windows native applications ignore Windows-Logo key state when checking
  // shortcut keys even if the key is pressed.  Therefore, if there is no
  // shortcut key which exactly matches current modifier state, we should
  // retry to look for a shortcut key without the Windows-Logo key press.
  if (!aIgnoreModifierState.mOS) {
    WidgetKeyboardEvent* keyEvent =
      aKeyEvent->AsEvent()->GetInternalNSEvent()->AsKeyboardEvent();
    if (keyEvent && keyEvent->IsOS()) {
      IgnoreModifierState ignoreModifierState(aIgnoreModifierState);
      ignoreModifierState.mOS = true;
      return WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler, aCharCode,
                                    ignoreModifierState, aExecute);
    }
  }
#endif

  return false;
}
Exemple #18
0
NS_IMETHODIMP
KeyboardEvent::GetKey(nsAString& aKeyName)
{
  WidgetKeyboardEvent* keyboardEvent = mEvent->AsKeyboardEvent();
  keyboardEvent->GetDOMKeyName(aKeyName);

  nsIDocument::DeprecatedOperations deprecatedOperation;
  switch (keyboardEvent->mKeyNameIndex) {
    case KEY_NAME_INDEX_Down:
      deprecatedOperation = nsIDocument::eKeyNameDown;
      break;
    case KEY_NAME_INDEX_Left:
      deprecatedOperation = nsIDocument::eKeyNameLeft;
      break;
    case KEY_NAME_INDEX_Right:
      deprecatedOperation = nsIDocument::eKeyNameRight;
      break;
    case KEY_NAME_INDEX_Up:
      deprecatedOperation = nsIDocument::eKeyNameUp;
      break;
    case KEY_NAME_INDEX_Crsel:
      deprecatedOperation = nsIDocument::eKeyNameCrsel;
      break;
    case KEY_NAME_INDEX_Del:
      deprecatedOperation = nsIDocument::eKeyNameDel;
      break;
    case KEY_NAME_INDEX_Exsel:
      deprecatedOperation = nsIDocument::eKeyNameExsel;
      break;
    case KEY_NAME_INDEX_Menu:
      deprecatedOperation = nsIDocument::eKeyNameMenu;
      break;
    case KEY_NAME_INDEX_Esc:
      deprecatedOperation = nsIDocument::eKeyNameEsc;
      break;
    case KEY_NAME_INDEX_Nonconvert:
      deprecatedOperation = nsIDocument::eKeyNameNonconvert;
      break;
    case KEY_NAME_INDEX_HalfWidth:
      deprecatedOperation = nsIDocument::eKeyNameHalfWidth;
      break;
    case KEY_NAME_INDEX_RomanCharacters:
      deprecatedOperation = nsIDocument::eKeyNameRomanCharacters;
      break;
    case KEY_NAME_INDEX_FullWidth:
      deprecatedOperation = nsIDocument::eKeyNameFullWidth;
      break;
    case KEY_NAME_INDEX_SelectMedia:
      deprecatedOperation = nsIDocument::eKeyNameSelectMedia;
      break;
    case KEY_NAME_INDEX_MediaNextTrack:
      deprecatedOperation = nsIDocument::eKeyNameMediaNextTrack;
      break;
    case KEY_NAME_INDEX_MediaPreviousTrack:
      deprecatedOperation = nsIDocument::eKeyNameMediaPreviousTrack;
      break;
    case KEY_NAME_INDEX_Red:
      deprecatedOperation = nsIDocument::eKeyNameRed;
      break;
    case KEY_NAME_INDEX_Green:
      deprecatedOperation = nsIDocument::eKeyNameGreen;
      break;
    case KEY_NAME_INDEX_Yellow:
      deprecatedOperation = nsIDocument::eKeyNameYellow;
      break;
    case KEY_NAME_INDEX_Blue:
      deprecatedOperation = nsIDocument::eKeyNameBlue;
      break;
    case KEY_NAME_INDEX_Live:
      deprecatedOperation = nsIDocument::eKeyNameLive;
      break;
    case KEY_NAME_INDEX_Apps:
      deprecatedOperation = nsIDocument::eKeyNameApps;
      break;
    case KEY_NAME_INDEX_FastFwd:
      deprecatedOperation = nsIDocument::eKeyNameFastFwd;
      break;
    case KEY_NAME_INDEX_Zoom:
      deprecatedOperation = nsIDocument::eKeyNameZoom;
      break;
    case KEY_NAME_INDEX_DeadGrave:
    case KEY_NAME_INDEX_DeadAcute:
    case KEY_NAME_INDEX_DeadCircumflex:
    case KEY_NAME_INDEX_DeadTilde:
    case KEY_NAME_INDEX_DeadMacron:
    case KEY_NAME_INDEX_DeadBreve:
    case KEY_NAME_INDEX_DeadAboveDot:
    case KEY_NAME_INDEX_DeadUmlaut:
    case KEY_NAME_INDEX_DeadAboveRing:
    case KEY_NAME_INDEX_DeadDoubleacute:
    case KEY_NAME_INDEX_DeadCaron:
    case KEY_NAME_INDEX_DeadCedilla:
    case KEY_NAME_INDEX_DeadOgonek:
    case KEY_NAME_INDEX_DeadIota:
    case KEY_NAME_INDEX_DeadVoicedSound:
    case KEY_NAME_INDEX_DeadSemivoicedSound:
      deprecatedOperation = nsIDocument::eKeyNameDeadKeys;
      break;
    default:
      return NS_OK;
  }

  nsIDocument* doc = mOwner ? mOwner->GetExtantDoc() : nullptr;
  if (NS_WARN_IF(!doc)) {
    return NS_OK;
  }
  doc->WarnOnceAbout(deprecatedOperation);
  return NS_OK;
}
Exemple #19
0
nsMenuFrame*
nsMenuBarFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent)
{
  uint32_t charCode;
  aKeyEvent->GetCharCode(&charCode);

  AutoTArray<uint32_t, 10> accessKeys;
  WidgetKeyboardEvent* nativeKeyEvent =
    aKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
  if (nativeKeyEvent) {
    nativeKeyEvent->GetAccessKeyCandidates(accessKeys);
  }
  if (accessKeys.IsEmpty() && charCode)
    accessKeys.AppendElement(charCode);

  if (accessKeys.IsEmpty())
    return nullptr; // no character was pressed so just return

  // Enumerate over our list of frames.
  auto insertion = PresContext()->PresShell()->FrameConstructor()->
    GetInsertionPoint(GetContent(), nullptr);
  nsContainerFrame* immediateParent = insertion.mParentFrame;
  if (!immediateParent)
    immediateParent = this;

  // Find a most preferred accesskey which should be returned.
  nsIFrame* foundMenu = nullptr;
  size_t foundIndex = accessKeys.NoIndex;
  nsIFrame* currFrame = immediateParent->PrincipalChildList().FirstChild();

  while (currFrame) {
    nsIContent* current = currFrame->GetContent();

    // See if it's a menu item.
    if (nsXULPopupManager::IsValidMenuItem(current, false)) {
      // Get the shortcut attribute.
      nsAutoString shortcutKey;
      current->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, shortcutKey);
      if (!shortcutKey.IsEmpty()) {
        ToLowerCase(shortcutKey);
        const char16_t* start = shortcutKey.BeginReading();
        const char16_t* end = shortcutKey.EndReading();
        uint32_t ch = UTF16CharEnumerator::NextChar(&start, end);
        size_t index = accessKeys.IndexOf(ch);
        if (index != accessKeys.NoIndex &&
            (foundIndex == accessKeys.NoIndex || index < foundIndex)) {
          foundMenu = currFrame;
          foundIndex = index;
        }
      }
    }
    currFrame = currFrame->GetNextSibling();
  }
  if (foundMenu) {
    return do_QueryFrame(foundMenu);
  }

  // didn't find a matching menu item
#ifdef XP_WIN
  // behavior on Windows - this item is on the menu bar, beep and deactivate the menu bar
  if (mIsActive) {
    nsCOMPtr<nsISound> soundInterface = do_CreateInstance("@mozilla.org/sound;1");
    if (soundInterface)
      soundInterface->Beep();
  }

  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
  if (pm) {
    nsIFrame* popup = pm->GetTopPopup(ePopupTypeAny);
    if (popup)
      pm->HidePopup(popup->GetContent(), true, true, true, false);
  }

  SetCurrentMenuItem(nullptr);
  SetActive(false);

#endif  // #ifdef XP_WIN

  return nullptr;
}