mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-11 16:32:59 +00:00
Bug 862519 - [e10s] Better handling of key commands also handled by content (r=smaug)
This commit is contained in:
parent
14278fe362
commit
e6388b7f5b
@ -1186,13 +1186,6 @@ var gBrowserInit = {
|
||||
WindowsPrefSync.init();
|
||||
}
|
||||
|
||||
if (gMultiProcessBrowser) {
|
||||
// Bug 862519 - Backspace doesn't work in electrolysis builds.
|
||||
// We bypass the problem by disabling the backspace-to-go-back command.
|
||||
document.getElementById("cmd_handleBackspace").setAttribute("disabled", true);
|
||||
document.getElementById("key_delete").setAttribute("disabled", true);
|
||||
}
|
||||
|
||||
SessionStore.promiseInitialized.then(() => {
|
||||
// Bail out if the window has been closed in the meantime.
|
||||
if (window.closed) {
|
||||
|
@ -334,6 +334,8 @@ parent:
|
||||
|
||||
__delete__();
|
||||
|
||||
ReplyKeyEvent(WidgetKeyboardEvent event);
|
||||
|
||||
child:
|
||||
/**
|
||||
* Notify the remote browser that it has been Show()n on this
|
||||
|
@ -1932,6 +1932,10 @@ TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event)
|
||||
mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
if (localEvent.mFlags.mWantReplyFromContentProcess) {
|
||||
SendReplyKeyEvent(localEvent);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1192,6 +1192,28 @@ TabParent::GetChildProcessOffset()
|
||||
pt, targetFrame->PresContext()->AppUnitsPerDevPixel()));
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvReplyKeyEvent(const WidgetKeyboardEvent& event)
|
||||
{
|
||||
NS_ENSURE_TRUE(mFrameElement, true);
|
||||
|
||||
WidgetKeyboardEvent localEvent(event);
|
||||
// Set mNoCrossProcessBoundaryForwarding to avoid this event from
|
||||
// being infinitely redispatched and forwarded to the child again.
|
||||
localEvent.mFlags.mNoCrossProcessBoundaryForwarding = true;
|
||||
|
||||
// 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);
|
||||
nsPresContext* presContext = presShell->GetPresContext();
|
||||
NS_ENSURE_TRUE(presContext, true);
|
||||
|
||||
EventDispatcher::Dispatch(mFrameElement, presContext, &localEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to answer query event using cached text.
|
||||
*
|
||||
|
@ -114,6 +114,7 @@ public:
|
||||
|
||||
virtual bool RecvMoveFocus(const bool& aForward) MOZ_OVERRIDE;
|
||||
virtual bool RecvEvent(const RemoteDOMEvent& aEvent) MOZ_OVERRIDE;
|
||||
virtual bool RecvReplyKeyEvent(const WidgetKeyboardEvent& event);
|
||||
virtual bool RecvPRenderFrameConstructor(PRenderFrameParent* actor) MOZ_OVERRIDE;
|
||||
virtual bool RecvInitRenderFrame(PRenderFrameParent* aFrame,
|
||||
ScrollingBehavior* scrolling,
|
||||
|
@ -585,6 +585,15 @@ nsXBLService::AttachGlobalKeyHandler(EventTarget* aTarget)
|
||||
manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keypress"),
|
||||
TrustedEventsAtSystemGroupBubble());
|
||||
|
||||
// The capturing listener is only used for XUL keysets to properly handle
|
||||
// shortcut keys in a multi-process environment.
|
||||
manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keydown"),
|
||||
TrustedEventsAtSystemGroupCapture());
|
||||
manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keyup"),
|
||||
TrustedEventsAtSystemGroupCapture());
|
||||
manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keypress"),
|
||||
TrustedEventsAtSystemGroupCapture());
|
||||
|
||||
if (contentNode)
|
||||
return contentNode->SetProperty(nsGkAtoms::listener,
|
||||
handler.forget().take(),
|
||||
@ -630,6 +639,13 @@ nsXBLService::DetachGlobalKeyHandler(EventTarget* aTarget)
|
||||
manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keypress"),
|
||||
TrustedEventsAtSystemGroupBubble());
|
||||
|
||||
manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keydown"),
|
||||
TrustedEventsAtSystemGroupCapture());
|
||||
manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keyup"),
|
||||
TrustedEventsAtSystemGroupCapture());
|
||||
manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keypress"),
|
||||
TrustedEventsAtSystemGroupCapture());
|
||||
|
||||
contentNode->DeleteProperty(nsGkAtoms::listener);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "nsEventStateManager.h"
|
||||
#include "nsIEditor.h"
|
||||
#include "nsIHTMLEditor.h"
|
||||
@ -276,24 +277,23 @@ nsXBLWindowKeyHandler::WalkHandlers(nsIDOMKeyEvent* aKeyEvent, nsIAtom* aEventTy
|
||||
nsresult rv = EnsureHandlers();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<Element> el = GetElement();
|
||||
bool isDisabled;
|
||||
nsCOMPtr<Element> el = GetElement(&isDisabled);
|
||||
if (!el) {
|
||||
if (mUserHandler) {
|
||||
WalkHandlersInternal(aKeyEvent, aEventType, mUserHandler);
|
||||
WalkHandlersInternal(aKeyEvent, aEventType, mUserHandler, true);
|
||||
aKeyEvent->GetDefaultPrevented(&prevent);
|
||||
if (prevent)
|
||||
return NS_OK; // Handled by the user bindings. Our work here is done.
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(el);
|
||||
// skip keysets that are disabled
|
||||
if (content && content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
|
||||
nsGkAtoms::_true, eCaseMatters)) {
|
||||
if (isDisabled) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
WalkHandlersInternal(aKeyEvent, aEventType, mHandler);
|
||||
WalkHandlersInternal(aKeyEvent, aEventType, mHandler, true);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -304,20 +304,50 @@ nsXBLWindowKeyHandler::HandleEvent(nsIDOMEvent* aEvent)
|
||||
nsCOMPtr<nsIDOMKeyEvent> keyEvent(do_QueryInterface(aEvent));
|
||||
NS_ENSURE_TRUE(keyEvent, NS_ERROR_INVALID_ARG);
|
||||
|
||||
uint16_t eventPhase;
|
||||
aEvent->GetEventPhase(&eventPhase);
|
||||
if (eventPhase == nsIDOMEvent::CAPTURING_PHASE) {
|
||||
HandleEventOnCapture(keyEvent);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoString eventType;
|
||||
aEvent->GetType(eventType);
|
||||
nsCOMPtr<nsIAtom> eventTypeAtom = do_GetAtom(eventType);
|
||||
NS_ENSURE_TRUE(eventTypeAtom, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
if (!mWeakPtrForElement) {
|
||||
nsCOMPtr<mozilla::dom::Element> originalTarget =
|
||||
do_QueryInterface(aEvent->GetInternalNSEvent()->originalTarget);
|
||||
if (nsEventStateManager::IsRemoteTarget(originalTarget)) {
|
||||
return NS_OK;
|
||||
}
|
||||
return WalkHandlers(keyEvent, eventTypeAtom);
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLWindowKeyHandler::HandleEventOnCapture(nsIDOMKeyEvent* aEvent)
|
||||
{
|
||||
WidgetKeyboardEvent* widgetEvent =
|
||||
aEvent->GetInternalNSEvent()->AsKeyboardEvent();
|
||||
|
||||
if (widgetEvent->mFlags.mNoCrossProcessBoundaryForwarding) {
|
||||
return;
|
||||
}
|
||||
|
||||
return WalkHandlers(keyEvent, eventTypeAtom);
|
||||
nsCOMPtr<mozilla::dom::Element> originalTarget =
|
||||
do_QueryInterface(aEvent->GetInternalNSEvent()->originalTarget);
|
||||
if (!nsEventStateManager::IsRemoteTarget(originalTarget)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HasHandlerForEvent(aEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If this event hasn't been marked as mNoCrossProcessBoundaryForwarding
|
||||
// yet, it means it wasn't processed by content. We'll not call any
|
||||
// of the handlers at this moment, and will wait for the event to be
|
||||
// redispatched with mNoCrossProcessBoundaryForwarding = 1 to process it.
|
||||
|
||||
// Inform the child process that this is a event that we want a reply
|
||||
// from.
|
||||
widgetEvent->mFlags.mWantReplyFromContentProcess = 1;
|
||||
aEvent->StopPropagation();
|
||||
}
|
||||
|
||||
//
|
||||
@ -391,29 +421,31 @@ nsXBLWindowKeyHandler::IsHTMLEditableFieldFocused()
|
||||
// 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 and then make it
|
||||
// so.
|
||||
// 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.
|
||||
//
|
||||
nsresult
|
||||
bool
|
||||
nsXBLWindowKeyHandler::WalkHandlersInternal(nsIDOMKeyEvent* aKeyEvent,
|
||||
nsIAtom* aEventType,
|
||||
nsXBLPrototypeHandler* aHandler)
|
||||
nsXBLPrototypeHandler* aHandler,
|
||||
bool aExecute)
|
||||
{
|
||||
nsAutoTArray<nsShortcutCandidate, 10> accessKeys;
|
||||
nsContentUtils::GetAccelKeyCandidates(aKeyEvent, accessKeys);
|
||||
|
||||
if (accessKeys.IsEmpty()) {
|
||||
WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler, 0, false);
|
||||
return NS_OK;
|
||||
return WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler,
|
||||
0, false, aExecute);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < accessKeys.Length(); ++i) {
|
||||
nsShortcutCandidate &key = accessKeys[i];
|
||||
if (WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler,
|
||||
key.mCharCode, key.mIgnoreShift))
|
||||
return NS_OK;
|
||||
key.mCharCode, key.mIgnoreShift, aExecute))
|
||||
return true;
|
||||
}
|
||||
return NS_OK;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -421,7 +453,8 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute(nsIDOMKeyEvent* aKeyEvent,
|
||||
nsIAtom* aEventType,
|
||||
nsXBLPrototypeHandler* aHandler,
|
||||
uint32_t aCharCode,
|
||||
bool aIgnoreShiftKey)
|
||||
bool aIgnoreShiftKey,
|
||||
bool aExecute)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
@ -491,6 +524,10 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute(nsIDOMKeyEvent* aKeyEvent,
|
||||
piTarget = mTarget;
|
||||
}
|
||||
|
||||
if (!aExecute) {
|
||||
return true;
|
||||
}
|
||||
|
||||
rv = currHandler->ExecuteHandler(piTarget, aKeyEvent);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return true;
|
||||
@ -500,10 +537,38 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute(nsIDOMKeyEvent* aKeyEvent,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsXBLWindowKeyHandler::HasHandlerForEvent(nsIDOMKeyEvent* aEvent)
|
||||
{
|
||||
if (!aEvent->InternalDOMEvent()->IsTrusted()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureHandlers();
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
bool isDisabled;
|
||||
nsCOMPtr<Element> el = GetElement(&isDisabled);
|
||||
if (el && isDisabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoString eventType;
|
||||
aEvent->GetType(eventType);
|
||||
nsCOMPtr<nsIAtom> eventTypeAtom = do_GetAtom(eventType);
|
||||
NS_ENSURE_TRUE(eventTypeAtom, false);
|
||||
|
||||
return WalkHandlersInternal(aEvent, eventTypeAtom, mHandler, false);
|
||||
}
|
||||
|
||||
already_AddRefed<Element>
|
||||
nsXBLWindowKeyHandler::GetElement()
|
||||
nsXBLWindowKeyHandler::GetElement(bool* aIsDisabled)
|
||||
{
|
||||
nsCOMPtr<Element> element = do_QueryReferent(mWeakPtrForElement);
|
||||
if (element && aIsDisabled) {
|
||||
*aIsDisabled = element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
|
||||
nsGkAtoms::_true, eCaseMatters);
|
||||
}
|
||||
return element.forget();
|
||||
}
|
||||
|
||||
|
@ -35,14 +35,23 @@ protected:
|
||||
nsresult WalkHandlers(nsIDOMKeyEvent* aKeyEvent, nsIAtom* aEventType);
|
||||
|
||||
// walk the handlers, looking for one to handle the event
|
||||
nsresult WalkHandlersInternal(nsIDOMKeyEvent* aKeyEvent,
|
||||
nsIAtom* aEventType,
|
||||
nsXBLPrototypeHandler* aHandler);
|
||||
bool WalkHandlersInternal(nsIDOMKeyEvent* aKeyEvent,
|
||||
nsIAtom* aEventType,
|
||||
nsXBLPrototypeHandler* aHandler,
|
||||
bool aExecute);
|
||||
|
||||
// walk the handlers for aEvent, aCharCode and aIgnoreShiftKey
|
||||
// walk the handlers for aEvent, aCharCode and aIgnoreShiftKey. Execute it
|
||||
// if aExecute = true.
|
||||
bool WalkHandlersAndExecute(nsIDOMKeyEvent* aKeyEvent, nsIAtom* aEventType,
|
||||
nsXBLPrototypeHandler* aHandler,
|
||||
uint32_t aCharCode, bool aIgnoreShiftKey);
|
||||
nsXBLPrototypeHandler* aHandler,
|
||||
uint32_t aCharCode, bool aIgnoreShiftKey,
|
||||
bool aExecute);
|
||||
|
||||
// HandleEvent function for the capturing phase.
|
||||
void HandleEventOnCapture(nsIDOMKeyEvent* aEvent);
|
||||
|
||||
// Check if any handler would handle the given event.
|
||||
bool HasHandlerForEvent(nsIDOMKeyEvent* aEvent);
|
||||
|
||||
// lazily load the handlers. Overridden to handle being attached
|
||||
// to a particular element rather than the document
|
||||
@ -57,8 +66,10 @@ protected:
|
||||
bool IsHTMLEditableFieldFocused();
|
||||
|
||||
// Returns the element which was passed as a parameter to the constructor,
|
||||
// unless the element has been removed from the document.
|
||||
already_AddRefed<mozilla::dom::Element> GetElement();
|
||||
// unless the element has been removed from the document. Optionally returns
|
||||
// whether the disabled attribute is set on the element (assuming the element
|
||||
// is non-null).
|
||||
already_AddRefed<mozilla::dom::Element> GetElement(bool* aIsDisabled = nullptr);
|
||||
// Using weak pointer to the DOM Element.
|
||||
nsWeakPtr mWeakPtrForElement;
|
||||
mozilla::dom::EventTarget* mTarget; // weak ref
|
||||
|
@ -553,6 +553,11 @@ public:
|
||||
bool mNoContentDispatch : 1;
|
||||
// If mOnlyChromeDispatch is true, the event is dispatched to only chrome.
|
||||
bool mOnlyChromeDispatch : 1;
|
||||
// If mWantReplyFromContentProcess is true, the event will be redispatched
|
||||
// in the parent process after the content process has handled it. Useful
|
||||
// for when the parent process need the know first how the event was used
|
||||
// by content before handling it itself.
|
||||
bool mWantReplyFromContentProcess : 1;
|
||||
|
||||
// If the event is being handled in target phase, returns true.
|
||||
inline bool InTargetPhase() const
|
||||
|
Loading…
Reference in New Issue
Block a user