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; }
// 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; }
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; }
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; }
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; }
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; }
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; }
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; }