Bug 1101975, handle access keys in content process before menus, r=masayuki

This commit is contained in:
Neil Deakin 2016-05-11 08:56:42 -04:00
Родитель 33054a51f2
Коммит 405358d4b3
20 изменённых файлов: 220 добавлений и 118 удалений

Просмотреть файл

@ -7134,7 +7134,7 @@ nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost)
return NS_OK;
}
void
bool
nsContentUtils::CallOnAllRemoteChildren(nsIMessageBroadcaster* aManager,
CallOnRemoteChildFunction aCallback,
void* aArg)
@ -7150,7 +7150,9 @@ nsContentUtils::CallOnAllRemoteChildren(nsIMessageBroadcaster* aManager,
nsCOMPtr<nsIMessageBroadcaster> nonLeafMM = do_QueryInterface(childMM);
if (nonLeafMM) {
CallOnAllRemoteChildren(nonLeafMM, aCallback, aArg);
if (CallOnAllRemoteChildren(nonLeafMM, aCallback, aArg)) {
return true;
}
continue;
}
@ -7162,10 +7164,14 @@ nsContentUtils::CallOnAllRemoteChildren(nsIMessageBroadcaster* aManager,
nsFrameLoader* fl = static_cast<nsFrameLoader*>(cb);
TabParent* remote = TabParent::GetFrom(fl);
if (remote && aCallback) {
aCallback(remote, aArg);
if (aCallback(remote, aArg)) {
return true;
}
}
}
}
return false;
}
void

Просмотреть файл

@ -171,7 +171,7 @@ struct EventNameMapping
mozilla::EventClassID mEventClassID;
};
typedef void (*CallOnRemoteChildFunction) (mozilla::dom::TabParent* aTabParent,
typedef bool (*CallOnRemoteChildFunction) (mozilla::dom::TabParent* aTabParent,
void* aArg);
class nsContentUtils
@ -2379,7 +2379,7 @@ public:
/*
* Call the given callback on all remote children of the given top-level
* window.
* window. Return true from the callback to stop calling further children.
*/
static void CallOnAllRemoteChildren(nsPIDOMWindowOuter* aWindow,
CallOnRemoteChildFunction aCallback,
@ -2598,7 +2598,7 @@ private:
static AutocompleteAttrState InternalSerializeAutocompleteAttribute(const nsAttrValue* aAttrVal,
mozilla::dom::AutocompleteInfo& aInfo);
static void CallOnAllRemoteChildren(nsIMessageBroadcaster* aManager,
static bool CallOnAllRemoteChildren(nsIMessageBroadcaster* aManager,
CallOnRemoteChildFunction aCallback,
void* aArg);

Просмотреть файл

@ -1110,11 +1110,12 @@ nsFocusManager::EnsureCurrentWidgetFocused()
}
}
void
bool
ActivateOrDeactivateChild(TabParent* aParent, void* aArg)
{
bool active = static_cast<bool>(aArg);
Unused << aParent->SendParentActivated(active);
return false;
}
void

Просмотреть файл

@ -682,6 +682,7 @@ GK_ATOM(ol, "ol")
GK_ATOM(omitXmlDeclaration, "omit-xml-declaration")
GK_ATOM(ona2dpstatuschanged, "ona2dpstatuschanged")
GK_ATOM(onabort, "onabort")
GK_ATOM(onmozaccesskeynotfound, "onmozaccesskeynotfound")
GK_ATOM(onactivate, "onactivate")
GK_ATOM(onadapteradded, "onadapteradded")
GK_ATOM(onadapterremoved, "onadapterremoved")

Просмотреть файл

@ -270,6 +270,10 @@ NON_IDL_EVENT(mozbrowserafterkeyup,
eAfterKeyUp,
EventNameType_None,
eBeforeAfterKeyboardEventClass)
NON_IDL_EVENT(mozaccesskeynotfound,
eAccessKeyNotFound,
EventNameType_None,
eKeyboardEventClass)
EVENT(loadeddata,
eLoadedData,
EventNameType_HTML,

Просмотреть файл

@ -732,15 +732,18 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
modifierMask |= NS_MODIFIER_OS;
// Prevent keyboard scrolling while an accesskey modifier is in use.
if (modifierMask &&
(modifierMask == Prefs::ChromeAccessModifierMask() ||
modifierMask == Prefs::ContentAccessModifierMask())) {
AutoTArray<uint32_t, 10> accessCharCodes;
keyEvent->GetAccessKeyCandidates(accessCharCodes);
if (modifierMask) {
bool matchesContentAccessKey = (modifierMask == Prefs::ContentAccessModifierMask());
if (modifierMask == Prefs::ChromeAccessModifierMask() ||
matchesContentAccessKey) {
AutoTArray<uint32_t, 10> accessCharCodes;
keyEvent->GetAccessKeyCandidates(accessCharCodes);
if (HandleAccessKey(aPresContext, accessCharCodes,
keyEvent->IsTrusted(), modifierMask)) {
*aStatus = nsEventStatus_eConsumeNoDefault;
if (HandleAccessKey(keyEvent, aPresContext, accessCharCodes,
modifierMask, matchesContentAccessKey)) {
*aStatus = nsEventStatus_eConsumeNoDefault;
}
}
}
}
@ -1036,21 +1039,21 @@ EventStateManager::GetAccessKeyLabelPrefix(Element* aElement, nsAString& aPrefix
}
}
struct AccessKeyInfo
struct MOZ_STACK_CLASS AccessKeyInfo
{
WidgetKeyboardEvent* event;
nsTArray<uint32_t>& charCodes;
bool isTrusted;
int32_t modifierMask;
AccessKeyInfo(nsTArray<uint32_t>& aCharCodes, bool aIsTrusted, int32_t aModifierMask)
: charCodes(aCharCodes)
, isTrusted(aIsTrusted)
AccessKeyInfo(WidgetKeyboardEvent* aEvent, nsTArray<uint32_t>& aCharCodes, int32_t aModifierMask)
: event(aEvent)
, charCodes(aCharCodes)
, modifierMask(aModifierMask)
{
}
};
static void
static bool
HandleAccessKeyInRemoteChild(TabParent* aTabParent, void* aArg)
{
AccessKeyInfo* accessKeyInfo = static_cast<AccessKeyInfo*>(aArg);
@ -1059,15 +1062,21 @@ HandleAccessKeyInRemoteChild(TabParent* aTabParent, void* aArg)
bool active;
aTabParent->GetDocShellIsActive(&active);
if (active) {
aTabParent->HandleAccessKey(accessKeyInfo->charCodes, accessKeyInfo->isTrusted,
accessKeyInfo->event->mAccessKeyForwardedToChild = true;
aTabParent->HandleAccessKey(*accessKeyInfo->event,
accessKeyInfo->charCodes,
accessKeyInfo->modifierMask);
return true;
}
return false;
}
bool
EventStateManager::HandleAccessKey(nsPresContext* aPresContext,
EventStateManager::HandleAccessKey(WidgetKeyboardEvent* aEvent,
nsPresContext* aPresContext,
nsTArray<uint32_t>& aAccessCharCodes,
bool aIsTrusted,
bool aMatchesContentAccessKey,
nsIDocShellTreeItem* aBubbledFrom,
ProcessingAccessKeyState aAccessKeyState,
int32_t aModifierMask)
@ -1082,7 +1091,7 @@ EventStateManager::HandleAccessKey(nsPresContext* aPresContext,
if (mAccessKeys.Count() > 0 &&
aModifierMask == GetAccessModifierMaskFor(docShell)) {
// Someone registered an accesskey. Find and activate it.
if (ExecuteAccessKey(aAccessCharCodes, aIsTrusted)) {
if (ExecuteAccessKey(aAccessCharCodes, aEvent->IsTrusted())) {
return true;
}
}
@ -1115,7 +1124,8 @@ EventStateManager::HandleAccessKey(nsPresContext* aPresContext,
static_cast<EventStateManager*>(subPC->EventStateManager());
if (esm &&
esm->HandleAccessKey(subPC, aAccessCharCodes, aIsTrusted, nullptr,
esm->HandleAccessKey(aEvent, subPC, aAccessCharCodes,
aMatchesContentAccessKey, nullptr,
eAccessKeyProcessingDown, aModifierMask)) {
return true;
}
@ -1137,22 +1147,27 @@ EventStateManager::HandleAccessKey(nsPresContext* aPresContext,
EventStateManager* esm =
static_cast<EventStateManager*>(parentPC->EventStateManager());
if (esm &&
esm->HandleAccessKey(parentPC, aAccessCharCodes, aIsTrusted, docShell,
eAccessKeyProcessingUp, aModifierMask)) {
esm->HandleAccessKey(aEvent, parentPC, aAccessCharCodes,
aMatchesContentAccessKey, docShell,
eAccessKeyProcessingDown, aModifierMask)) {
return true;
}
}
}// if end. bubble up process
// Now try remote children
if (mDocument && mDocument->GetWindow()) {
// If the content access key modifier is pressed, try remote children
if (aMatchesContentAccessKey && mDocument && mDocument->GetWindow()) {
// If the focus is currently on a node with a TabParent, the key event will
// get forwarded to the child process and HandleAccessKey called from there.
// If focus is somewhere else, then we need to check the remote children.
nsFocusManager* fm = nsFocusManager::GetFocusManager();
nsIContent* focusedContent = fm ? fm->GetFocusedContent() : nullptr;
if (!TabParent::GetFrom(focusedContent)) {
AccessKeyInfo accessKeyInfo(aAccessCharCodes, aIsTrusted, aModifierMask);
if (TabParent::GetFrom(focusedContent)) {
// A remote child process is focused. The key event should get sent to
// the child process.
aEvent->mAccessKeyForwardedToChild = true;
} else {
AccessKeyInfo accessKeyInfo(aEvent, aAccessCharCodes, aModifierMask);
nsContentUtils::CallOnAllRemoteChildren(mDocument->GetWindow(),
HandleAccessKeyInRemoteChild, &accessKeyInfo);
}

Просмотреть файл

@ -183,13 +183,15 @@ public:
static void GetAccessKeyLabelPrefix(dom::Element* aElement, nsAString& aPrefix);
bool HandleAccessKey(nsPresContext* aPresContext,
bool HandleAccessKey(WidgetKeyboardEvent* aEvent,
nsPresContext* aPresContext,
nsTArray<uint32_t>& aAccessCharCodes,
bool aIsTrusted,
int32_t aModifierMask)
int32_t aModifierMask,
bool aMatchesContentAccessKey)
{
return HandleAccessKey(aPresContext, aAccessCharCodes, aIsTrusted,
nullptr, eAccessKeyProcessingNormal, aModifierMask);
return HandleAccessKey(aEvent, aPresContext, aAccessCharCodes,
aMatchesContentAccessKey, nullptr,
eAccessKeyProcessingNormal, aModifierMask);
}
nsresult SetCursor(int32_t aCursor, imgIContainer* aContainer,
@ -435,9 +437,10 @@ protected:
* on descendant docshells first, then on the ancestor (with |aBubbledFrom|
* set to the docshell associated with |this|), until something matches.
*
* @param aEvent the keyboard event triggering the acccess key
* @param aPresContext the presentation context
* @param aAccessCharCodes list of charcode candidates
* @param aIsTrusted true if triggered by a trusted key event
* @param aMatchesContentAccessKey true if the content accesskey modifier is pressed
* @param aBubbledFrom is used by an ancestor to avoid calling HandleAccessKey()
* on the child the call originally came from, i.e. this is the child
* that recursively called us in its Up phase. The initial caller
@ -447,15 +450,16 @@ protected:
* processing children and Up when recursively calling its ancestor.
* @param aModifierMask modifier mask for the key event
*/
bool HandleAccessKey(nsPresContext* aPresContext,
nsTArray<uint32_t>& aAccessCharCodes,
bool aIsTrusted,
nsIDocShellTreeItem* aBubbledFrom,
ProcessingAccessKeyState aAccessKeyState,
int32_t aModifierMask);
bool HandleAccessKey(WidgetKeyboardEvent* aEvent,
nsPresContext* aPresContext,
nsTArray<uint32_t>& aAccessCharCodes,
bool aMatchesContentAccessKey,
nsIDocShellTreeItem* aBubbledFrom,
ProcessingAccessKeyState aAccessKeyState,
int32_t aModifierMask);
bool ExecuteAccessKey(nsTArray<uint32_t>& aAccessCharCodes,
bool aIsTrustedEvent);
bool aIsTrustedEvent);
//---------------------------------------------
// DocShell Focus Traversal Methods

Просмотреть файл

@ -198,6 +198,7 @@ KeyboardEvent::CharCode()
case eAfterKeyUp:
return 0;
case eKeyPress:
case eAccessKeyNotFound:
return mEvent->AsKeyboardEvent()->charCode;
default:
break;

Просмотреть файл

@ -506,6 +506,8 @@ parent:
*/
sync GetTabCount() returns (uint32_t value);
async AccessKeyNotHandled(WidgetKeyboardEvent event);
child:
async NativeSynthesisResponse(uint64_t aObserverId, nsCString aResponse);
@ -746,11 +748,12 @@ child:
* A potential accesskey was just pressed. Look for accesskey targets
* using the list of provided charCodes.
*
* @param charCode array of potential character codes
* @param event keyboard event
* @param isTrusted true if triggered by a trusted key event
* @param modifierMask indicates which accesskey modifiers are pressed
*/
async HandleAccessKey(uint32_t[] charCodes, bool isTrusted, int32_t modifierMask);
async HandleAccessKey(WidgetKeyboardEvent event,
uint32_t[] charCodes, int32_t modifierMask);
/**
* Propagate a refresh to the child process

Просмотреть файл

@ -2124,10 +2124,17 @@ TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event,
mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault;
}
// If a response is desired from the content process, resend the key event.
// If mAccessKeyForwardedToChild is set, then don't resend the key event yet
// as RecvHandleAccessKey will do this.
if (localEvent.mFlags.mWantReplyFromContentProcess) {
SendReplyKeyEvent(localEvent);
}
if (localEvent.mAccessKeyForwardedToChild) {
SendAccessKeyNotHandled(localEvent);
}
if (PresShell::BeforeAfterKeyboardEventEnabled()) {
SendDispatchAfterKeyboardEvent(localEvent);
}
@ -2390,8 +2397,8 @@ TabChild::RecvSwappedWithOtherRemoteLoader(const IPCTabContext& aContext)
}
bool
TabChild::RecvHandleAccessKey(nsTArray<uint32_t>&& aCharCodes,
const bool& aIsTrusted,
TabChild::RecvHandleAccessKey(const WidgetKeyboardEvent& aEvent,
nsTArray<uint32_t>&& aCharCodes,
const int32_t& aModifierMask)
{
nsCOMPtr<nsIDocument> document(GetDocument());
@ -2399,7 +2406,16 @@ TabChild::RecvHandleAccessKey(nsTArray<uint32_t>&& aCharCodes,
if (presShell) {
nsPresContext* pc = presShell->GetPresContext();
if (pc) {
pc->EventStateManager()->HandleAccessKey(pc, aCharCodes, aIsTrusted, aModifierMask);
if (!pc->EventStateManager()->
HandleAccessKey(&(const_cast<WidgetKeyboardEvent&>(aEvent)),
pc, aCharCodes,
aModifierMask, true)) {
// If no accesskey was found, inform the parent so that accesskeys on
// menus can be handled.
WidgetKeyboardEvent localEvent(aEvent);
localEvent.mWidget = mPuppetWidget;
SendAccessKeyNotHandled(localEvent);
}
}
}

Просмотреть файл

@ -566,8 +566,8 @@ public:
virtual bool
RecvThemeChanged(nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache) override;
virtual bool RecvHandleAccessKey(nsTArray<uint32_t>&& aCharCodes,
const bool& aIsTrusted,
virtual bool RecvHandleAccessKey(const WidgetKeyboardEvent& aEvent,
nsTArray<uint32_t>&& aCharCodes,
const int32_t& aModifierMask) override;
virtual bool RecvAudioChannelChangeNotification(const uint32_t& aAudioChannel,

Просмотреть файл

@ -988,12 +988,12 @@ TabParent::ThemeChanged()
}
void
TabParent::HandleAccessKey(nsTArray<uint32_t>& aCharCodes,
const bool& aIsTrusted,
TabParent::HandleAccessKey(const WidgetKeyboardEvent& aEvent,
nsTArray<uint32_t>& aCharCodes,
const int32_t& aModifierMask)
{
if (!mIsDestroyed) {
Unused << SendHandleAccessKey(aCharCodes, aIsTrusted, aModifierMask);
Unused << SendHandleAccessKey(aEvent, aCharCodes, aModifierMask);
}
}
@ -2130,6 +2130,31 @@ TabParent::RecvDispatchAfterKeyboardEvent(const WidgetKeyboardEvent& aEvent)
return true;
}
bool
TabParent::RecvAccessKeyNotHandled(const WidgetKeyboardEvent& aEvent)
{
NS_ENSURE_TRUE(mFrameElement, true);
WidgetKeyboardEvent localEvent(aEvent);
localEvent.mMessage = eAccessKeyNotFound;
localEvent.mAccessKeyForwardedToChild = false;
// Here we convert the WidgetEvent that we received to an nsIDOMEvent
// to be able to dispatch it to the <browser> element as the target element.
nsIDocument* doc = mFrameElement->OwnerDoc();
nsIPresShell* presShell = doc->GetShell();
NS_ENSURE_TRUE(presShell, true);
if (presShell->CanDispatchEvent()) {
nsPresContext* presContext = presShell->GetPresContext();
NS_ENSURE_TRUE(presContext, true);
EventDispatcher::Dispatch(mFrameElement, presContext, &localEvent);
}
return true;
}
bool
TabParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent)
{

Просмотреть файл

@ -174,6 +174,9 @@ public:
virtual bool
RecvDispatchAfterKeyboardEvent(const WidgetKeyboardEvent& aEvent) override;
virtual bool
RecvAccessKeyNotHandled(const WidgetKeyboardEvent& aEvent) override;
virtual bool RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
PRenderFrameParent* aRenderFrame,
const nsString& aURL,
@ -364,8 +367,8 @@ public:
void ThemeChanged();
void HandleAccessKey(nsTArray<uint32_t>& aCharCodes,
const bool& aIsTrusted,
void HandleAccessKey(const WidgetKeyboardEvent& aEvent,
nsTArray<uint32_t>& aCharCodes,
const int32_t& aModifierMask);
void Activate();

Просмотреть файл

@ -1596,10 +1596,11 @@ nsPresContext::ThemeChanged()
}
}
static void
static bool
NotifyThemeChanged(TabParent* aTabParent, void* aArg)
{
aTabParent->ThemeChanged();
return false;
}
void
@ -1948,11 +1949,12 @@ nsPresContext::HandleMediaFeatureValuesChangedEvent()
}
}
static void
static bool
NotifyTabSizeModeChanged(TabParent* aTab, void* aArg)
{
nsSizeMode* sizeMode = static_cast<nsSizeMode*>(aArg);
aTab->SizeModeChanged(*sizeMode);
return false;
}
void

Просмотреть файл

@ -79,6 +79,7 @@ nsMenuBarFrame::Init(nsIContent* aContent,
mTarget->AddSystemEventListener(NS_LITERAL_STRING("keypress"), mMenuBarListener, false);
mTarget->AddSystemEventListener(NS_LITERAL_STRING("keydown"), mMenuBarListener, false);
mTarget->AddSystemEventListener(NS_LITERAL_STRING("keyup"), mMenuBarListener, false);
mTarget->AddSystemEventListener(NS_LITERAL_STRING("mozaccesskeynotfound"), mMenuBarListener, false);
// mousedown event should be handled in all phase
mTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, true);
@ -416,6 +417,7 @@ nsMenuBarFrame::DestroyFrom(nsIFrame* aDestructRoot)
mTarget->RemoveSystemEventListener(NS_LITERAL_STRING("keypress"), mMenuBarListener, false);
mTarget->RemoveSystemEventListener(NS_LITERAL_STRING("keydown"), mMenuBarListener, false);
mTarget->RemoveSystemEventListener(NS_LITERAL_STRING("keyup"), mMenuBarListener, false);
mTarget->RemoveSystemEventListener(NS_LITERAL_STRING("mozaccesskeynotfound"), mMenuBarListener, false);
mTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, true);
mTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, false);

Просмотреть файл

@ -199,83 +199,82 @@ nsMenuBarListener::KeyPress(nsIDOMEvent* aKeyEvent)
aKeyEvent->GetIsTrusted(&trustedEvent);
}
if (!trustedEvent)
if (!trustedEvent) {
return NS_OK;
}
nsresult retVal = NS_OK; // default is to not consume event
InitAccessKey();
if (mAccessKey)
{
bool preventDefault;
aKeyEvent->GetDefaultPrevented(&preventDefault);
if (!preventDefault) {
nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
uint32_t keyCode, charCode;
keyEvent->GetKeyCode(&keyCode);
keyEvent->GetCharCode(&charCode);
// If accesskey handling was forwarded to a child process, wait for
// the mozaccesskeynotfound event before handling accesskeys.
WidgetKeyboardEvent* nativeKeyEvent =
aKeyEvent->WidgetEventPtr()->AsKeyboardEvent();
if (nativeKeyEvent->mAccessKeyForwardedToChild) {
return NS_OK;
}
bool hasAccessKeyCandidates = charCode != 0;
if (!hasAccessKeyCandidates) {
WidgetKeyboardEvent* nativeKeyEvent =
aKeyEvent->WidgetEventPtr()->AsKeyboardEvent();
if (nativeKeyEvent) {
AutoTArray<uint32_t, 10> keys;
nativeKeyEvent->GetAccessKeyCandidates(keys);
hasAccessKeyCandidates = !keys.IsEmpty();
}
nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
uint32_t keyCode, charCode;
keyEvent->GetKeyCode(&keyCode);
keyEvent->GetCharCode(&charCode);
bool hasAccessKeyCandidates = charCode != 0;
if (!hasAccessKeyCandidates) {
if (nativeKeyEvent) {
AutoTArray<uint32_t, 10> keys;
nativeKeyEvent->GetAccessKeyCandidates(keys);
hasAccessKeyCandidates = !keys.IsEmpty();
}
}
// Cancel the access key flag unless we are pressing the access key.
if (keyCode != (uint32_t)mAccessKey) {
mAccessKeyDownCanceled = true;
// Cancel the access key flag unless we are pressing the access key.
if (keyCode != (uint32_t)mAccessKey) {
mAccessKeyDownCanceled = true;
}
if (IsAccessKeyPressed(keyEvent) && hasAccessKeyCandidates) {
// Do shortcut navigation.
// A letter was pressed. We want to see if a shortcut gets matched. If
// so, we'll know the menu got activated.
nsMenuFrame* result = mMenuBarFrame->FindMenuWithShortcut(keyEvent);
if (result) {
mMenuBarFrame->SetActiveByKeyboard();
mMenuBarFrame->SetActive(true);
result->OpenMenu(true);
// The opened menu will listen next keyup event.
// Therefore, we should clear the keydown flags here.
mAccessKeyDown = mAccessKeyDownCanceled = false;
aKeyEvent->StopPropagation();
aKeyEvent->PreventDefault();
}
}
#ifndef XP_MACOSX
// Also need to handle F10 specially on Non-Mac platform.
else if (nativeKeyEvent->mMessage == eKeyPress && keyCode == NS_VK_F10) {
if ((GetModifiersForAccessKey(keyEvent) & ~MODIFIER_CONTROL) == 0) {
// The F10 key just went down by itself or with ctrl pressed.
// In Windows, both of these activate the menu bar.
mMenuBarFrame->SetActiveByKeyboard();
ToggleMenuActiveState();
if (IsAccessKeyPressed(keyEvent) && hasAccessKeyCandidates) {
// Do shortcut navigation.
// A letter was pressed. We want to see if a shortcut gets matched. If
// so, we'll know the menu got activated.
nsMenuFrame* result = mMenuBarFrame->FindMenuWithShortcut(keyEvent);
if (result) {
mMenuBarFrame->SetActiveByKeyboard();
mMenuBarFrame->SetActive(true);
result->OpenMenu(true);
// The opened menu will listen next keyup event.
// Therefore, we should clear the keydown flags here.
mAccessKeyDown = mAccessKeyDownCanceled = false;
if (mMenuBarFrame->IsActive()) {
#ifdef MOZ_WIDGET_GTK
// In GTK, this also opens the first menu.
mMenuBarFrame->GetCurrentMenuItem()->OpenMenu(true);
#endif
aKeyEvent->StopPropagation();
aKeyEvent->PreventDefault();
retVal = NS_OK; // I am consuming event
}
}
#ifndef XP_MACOSX
// Also need to handle F10 specially on Non-Mac platform.
else if (keyCode == NS_VK_F10) {
if ((GetModifiersForAccessKey(keyEvent) & ~MODIFIER_CONTROL) == 0) {
// The F10 key just went down by itself or with ctrl pressed.
// In Windows, both of these activate the menu bar.
mMenuBarFrame->SetActiveByKeyboard();
ToggleMenuActiveState();
if (mMenuBarFrame->IsActive()) {
#ifdef MOZ_WIDGET_GTK
// In GTK, this also opens the first menu.
mMenuBarFrame->GetCurrentMenuItem()->OpenMenu(true);
#endif
aKeyEvent->StopPropagation();
aKeyEvent->PreventDefault();
return NS_OK; // consume the event
}
}
}
}
#endif // !XP_MACOSX
}
}
return retVal;
return NS_OK;
}
bool
@ -425,6 +424,9 @@ nsMenuBarListener::HandleEvent(nsIDOMEvent* aEvent)
if (eventType.EqualsLiteral("keypress")) {
return KeyPress(aEvent);
}
if (eventType.EqualsLiteral("mozaccesskeynotfound")) {
return KeyPress(aEvent);
}
if (eventType.EqualsLiteral("blur")) {
return Blur(aEvent);
}

Просмотреть файл

@ -52,6 +52,12 @@ NS_EVENT_MESSAGE(eAfterKeyDown)
NS_EVENT_MESSAGE(eBeforeKeyUp)
NS_EVENT_MESSAGE(eAfterKeyUp)
// This message is sent after a content process handles a key event or accesskey
// to indicate that an potential accesskey was not found. The parent process may
// then respond by, for example, opening menus and processing other shortcuts.
// It inherits its properties from a keypress event.
NS_EVENT_MESSAGE(eAccessKeyNotFound)
NS_EVENT_MESSAGE(eResize)
NS_EVENT_MESSAGE(eScroll)

Просмотреть файл

@ -110,6 +110,7 @@ protected:
, mIsRepeat(false)
, mIsComposing(false)
, mIsReserved(false)
, mAccessKeyForwardedToChild(false)
, mKeyNameIndex(mozilla::KEY_NAME_INDEX_Unidentified)
, mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN)
, mNativeKeyEvent(nullptr)
@ -138,6 +139,7 @@ public:
, mIsRepeat(false)
, mIsComposing(false)
, mIsReserved(false)
, mAccessKeyForwardedToChild(false)
, mKeyNameIndex(mozilla::KEY_NAME_INDEX_Unidentified)
, mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN)
, mNativeKeyEvent(nullptr)
@ -220,6 +222,11 @@ public:
// Indicates if the key combination is reserved by chrome. This is set by
// nsXBLWindowKeyHandler at capturing phase of the default event group.
bool mIsReserved;
// True if accesskey handling was forwarded to the child via
// TabParent::HandleAccessKey. In this case, parent process menu access key
// handling should be delayed until it is determined that there exists no
// overriding access key in the content process.
bool mAccessKeyForwardedToChild;
// DOM KeyboardEvent.key
KeyNameIndex mKeyNameIndex;
// DOM KeyboardEvent.code
@ -374,6 +381,7 @@ public:
mIsRepeat = aEvent.mIsRepeat;
mIsComposing = aEvent.mIsComposing;
mIsReserved = aEvent.mIsReserved;
mAccessKeyForwardedToChild = aEvent.mAccessKeyForwardedToChild;
mKeyNameIndex = aEvent.mKeyNameIndex;
mCodeNameIndex = aEvent.mCodeNameIndex;
mKeyValue = aEvent.mKeyValue;

Просмотреть файл

@ -171,6 +171,7 @@ WidgetEvent::HasKeyEventMessage() const
case eBeforeKeyUp:
case eAfterKeyDown:
case eAfterKeyUp:
case eAccessKeyNotFound:
return true;
default:
return false;

Просмотреть файл

@ -399,6 +399,7 @@ struct ParamTraits<mozilla::WidgetKeyboardEvent>
WriteParam(aMsg, aParam.isChar);
WriteParam(aMsg, aParam.mIsRepeat);
WriteParam(aMsg, aParam.mIsReserved);
WriteParam(aMsg, aParam.mAccessKeyForwardedToChild);
WriteParam(aMsg, aParam.location);
WriteParam(aMsg, aParam.mUniqueId);
WriteParam(aMsg, aParam.mIsSynthesizedByTIP);
@ -434,6 +435,7 @@ struct ParamTraits<mozilla::WidgetKeyboardEvent>
ReadParam(aMsg, aIter, &aResult->isChar) &&
ReadParam(aMsg, aIter, &aResult->mIsRepeat) &&
ReadParam(aMsg, aIter, &aResult->mIsReserved) &&
ReadParam(aMsg, aIter, &aResult->mAccessKeyForwardedToChild) &&
ReadParam(aMsg, aIter, &aResult->location) &&
ReadParam(aMsg, aIter, &aResult->mUniqueId) &&
ReadParam(aMsg, aIter, &aResult->mIsSynthesizedByTIP) &&