2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 04:12:37 -07:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsXBLPrototypeHandler.h"
|
|
|
|
#include "nsXBLWindowKeyHandler.h"
|
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIAtom.h"
|
|
|
|
#include "nsIDOMKeyEvent.h"
|
|
|
|
#include "nsXBLService.h"
|
|
|
|
#include "nsIServiceManager.h"
|
|
|
|
#include "nsGkAtoms.h"
|
2010-07-14 18:53:11 -07:00
|
|
|
#include "nsXBLDocumentInfo.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIDOMElement.h"
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
#include "nsFocusManager.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIURI.h"
|
|
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "nsContentUtils.h"
|
|
|
|
#include "nsXBLPrototypeBinding.h"
|
|
|
|
#include "nsPIDOMWindow.h"
|
|
|
|
#include "nsIDocShell.h"
|
|
|
|
#include "nsIPresShell.h"
|
2014-03-31 21:09:23 -07:00
|
|
|
#include "mozilla/EventStateManager.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsISelectionController.h"
|
2011-05-28 00:03:00 -07:00
|
|
|
#include "mozilla/Preferences.h"
|
2013-09-25 04:21:19 -07:00
|
|
|
#include "mozilla/TextEvents.h"
|
2011-07-20 12:18:54 -07:00
|
|
|
#include "mozilla/dom/Element.h"
|
2014-03-18 08:16:47 -07:00
|
|
|
#include "mozilla/dom/Event.h"
|
2014-01-22 19:18:51 -08:00
|
|
|
#include "nsIEditor.h"
|
|
|
|
#include "nsIHTMLEditor.h"
|
2014-02-10 11:55:01 -08:00
|
|
|
#include "nsIDOMDocument.h"
|
2011-05-28 00:03:00 -07:00
|
|
|
|
|
|
|
using namespace mozilla;
|
2013-04-05 17:44:26 -07:00
|
|
|
using namespace mozilla::dom;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-10-14 09:15:12 -07:00
|
|
|
class nsXBLSpecialDocInfo : public nsIObserver
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
public:
|
2010-07-14 18:53:11 -07:00
|
|
|
nsRefPtr<nsXBLDocumentInfo> mHTMLBindings;
|
|
|
|
nsRefPtr<nsXBLDocumentInfo> mUserHTMLBindings;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
static const char sHTMLBindingStr[];
|
|
|
|
static const char sUserHTMLBindingStr[];
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool mInitialized;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
public:
|
2012-10-14 09:15:12 -07:00
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NS_DECL_NSIOBSERVER
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void LoadDocInfo();
|
|
|
|
void GetAllHandlers(const char* aType,
|
|
|
|
nsXBLPrototypeHandler** handler,
|
|
|
|
nsXBLPrototypeHandler** userHandler);
|
2010-07-14 18:53:11 -07:00
|
|
|
void GetHandlers(nsXBLDocumentInfo* aInfo,
|
2007-03-22 10:30:00 -07:00
|
|
|
const nsACString& aRef,
|
|
|
|
nsXBLPrototypeHandler** aResult);
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
nsXBLSpecialDocInfo() : mInitialized(false) {}
|
2012-10-14 09:15:12 -07:00
|
|
|
|
2014-06-23 12:56:07 -07:00
|
|
|
protected:
|
2012-10-14 09:15:12 -07:00
|
|
|
virtual ~nsXBLSpecialDocInfo() {}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
const char nsXBLSpecialDocInfo::sHTMLBindingStr[] =
|
|
|
|
"chrome://global/content/platformHTMLBindings.xml";
|
|
|
|
|
2014-04-27 00:06:00 -07:00
|
|
|
NS_IMPL_ISUPPORTS(nsXBLSpecialDocInfo, nsIObserver)
|
2012-10-14 09:15:12 -07:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLSpecialDocInfo::Observe(nsISupports* aSubject,
|
|
|
|
const char* aTopic,
|
2014-01-04 07:02:17 -08:00
|
|
|
const char16_t* aData)
|
2012-10-14 09:15:12 -07:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"), "wrong topic");
|
|
|
|
|
|
|
|
// On shutdown, clear our fields to avoid an extra cycle collection.
|
|
|
|
mHTMLBindings = nullptr;
|
|
|
|
mUserHTMLBindings = nullptr;
|
|
|
|
mInitialized = false;
|
|
|
|
nsContentUtils::UnregisterShutdownObserver(this);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void nsXBLSpecialDocInfo::LoadDocInfo()
|
|
|
|
{
|
|
|
|
if (mInitialized)
|
|
|
|
return;
|
2011-10-17 07:59:28 -07:00
|
|
|
mInitialized = true;
|
2012-10-14 09:15:12 -07:00
|
|
|
nsContentUtils::RegisterShutdownObserver(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-05-23 11:46:04 -07:00
|
|
|
nsXBLService* xblService = nsXBLService::GetInstance();
|
|
|
|
if (!xblService)
|
2007-03-22 10:30:00 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Obtain the platform doc info
|
|
|
|
nsCOMPtr<nsIURI> bindingURI;
|
|
|
|
NS_NewURI(getter_AddRefs(bindingURI), sHTMLBindingStr);
|
|
|
|
if (!bindingURI) {
|
|
|
|
return;
|
|
|
|
}
|
2012-07-30 07:20:58 -07:00
|
|
|
xblService->LoadBindingDocumentInfo(nullptr, nullptr,
|
2007-03-22 10:30:00 -07:00
|
|
|
bindingURI,
|
2012-07-30 07:20:58 -07:00
|
|
|
nullptr,
|
2011-10-17 07:59:28 -07:00
|
|
|
true,
|
2007-03-22 10:30:00 -07:00
|
|
|
getter_AddRefs(mHTMLBindings));
|
|
|
|
|
|
|
|
const nsAdoptingCString& userHTMLBindingStr =
|
2011-05-28 00:03:00 -07:00
|
|
|
Preferences::GetCString("dom.userHTMLBindings.uri");
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!userHTMLBindingStr.IsEmpty()) {
|
|
|
|
NS_NewURI(getter_AddRefs(bindingURI), userHTMLBindingStr);
|
|
|
|
if (!bindingURI) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
xblService->LoadBindingDocumentInfo(nullptr, nullptr,
|
2007-03-22 10:30:00 -07:00
|
|
|
bindingURI,
|
2012-07-30 07:20:58 -07:00
|
|
|
nullptr,
|
2011-10-17 07:59:28 -07:00
|
|
|
true,
|
2007-03-22 10:30:00 -07:00
|
|
|
getter_AddRefs(mUserHTMLBindings));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// GetHandlers
|
|
|
|
//
|
|
|
|
//
|
|
|
|
void
|
2010-07-14 18:53:11 -07:00
|
|
|
nsXBLSpecialDocInfo::GetHandlers(nsXBLDocumentInfo* aInfo,
|
2007-03-22 10:30:00 -07:00
|
|
|
const nsACString& aRef,
|
|
|
|
nsXBLPrototypeHandler** aResult)
|
|
|
|
{
|
2010-07-14 18:55:54 -07:00
|
|
|
nsXBLPrototypeBinding* binding = aInfo->GetPrototypeBinding(aRef);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
NS_ASSERTION(binding, "No binding found for the XBL window key handler.");
|
|
|
|
if (!binding)
|
|
|
|
return;
|
|
|
|
|
|
|
|
*aResult = binding->GetPrototypeHandlers();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsXBLSpecialDocInfo::GetAllHandlers(const char* aType,
|
|
|
|
nsXBLPrototypeHandler** aHandler,
|
|
|
|
nsXBLPrototypeHandler** aUserHandler)
|
|
|
|
{
|
|
|
|
if (mUserHTMLBindings) {
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString type(aType);
|
2014-05-21 20:48:51 -07:00
|
|
|
type.AppendLiteral("User");
|
2007-03-22 10:30:00 -07:00
|
|
|
GetHandlers(mUserHTMLBindings, type, aUserHandler);
|
|
|
|
}
|
|
|
|
if (mHTMLBindings) {
|
|
|
|
GetHandlers(mHTMLBindings, nsDependentCString(aType), aHandler);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Init statics
|
2012-07-30 07:20:58 -07:00
|
|
|
nsXBLSpecialDocInfo* nsXBLWindowKeyHandler::sXBLSpecialDocInfo = nullptr;
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t nsXBLWindowKeyHandler::sRefCnt = 0;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-05-14 02:11:38 -07:00
|
|
|
nsXBLWindowKeyHandler::nsXBLWindowKeyHandler(nsIDOMElement* aElement,
|
2013-04-14 11:27:33 -07:00
|
|
|
EventTarget* aTarget)
|
2007-05-14 02:11:38 -07:00
|
|
|
: mTarget(aTarget),
|
2012-07-30 07:20:58 -07:00
|
|
|
mHandler(nullptr),
|
|
|
|
mUserHandler(nullptr)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
mWeakPtrForElement = do_GetWeakReference(aElement);
|
|
|
|
++sRefCnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsXBLWindowKeyHandler::~nsXBLWindowKeyHandler()
|
|
|
|
{
|
|
|
|
// If mWeakPtrForElement is non-null, we created a prototype handler.
|
|
|
|
if (mWeakPtrForElement)
|
|
|
|
delete mHandler;
|
|
|
|
|
|
|
|
--sRefCnt;
|
|
|
|
if (!sRefCnt) {
|
2012-10-14 09:15:12 -07:00
|
|
|
NS_IF_RELEASE(sXBLSpecialDocInfo);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-27 00:06:00 -07:00
|
|
|
NS_IMPL_ISUPPORTS(nsXBLWindowKeyHandler,
|
|
|
|
nsIDOMEventListener)
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
static void
|
|
|
|
BuildHandlerChain(nsIContent* aContent, nsXBLPrototypeHandler** aResult)
|
|
|
|
{
|
2012-07-30 07:20:58 -07:00
|
|
|
*aResult = nullptr;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Since we chain each handler onto the next handler,
|
|
|
|
// we'll enumerate them here in reverse so that when we
|
|
|
|
// walk the chain they'll come out in the original order
|
2011-09-27 00:54:58 -07:00
|
|
|
for (nsIContent* key = aContent->GetLastChild();
|
|
|
|
key;
|
|
|
|
key = key->GetPreviousSibling()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (key->NodeInfo()->Equals(nsGkAtoms::key, kNameSpaceID_XUL)) {
|
2008-04-14 21:16:24 -07:00
|
|
|
// Check whether the key element has empty value at key/char attribute.
|
|
|
|
// Such element is used by localizers for alternative shortcut key
|
|
|
|
// definition on the locale. See bug 426501.
|
2008-04-23 01:04:08 -07:00
|
|
|
nsAutoString valKey, valCharCode, valKeyCode;
|
2011-09-28 23:19:26 -07:00
|
|
|
bool attrExists =
|
2008-04-23 01:04:08 -07:00
|
|
|
key->GetAttr(kNameSpaceID_None, nsGkAtoms::key, valKey) ||
|
|
|
|
key->GetAttr(kNameSpaceID_None, nsGkAtoms::charcode, valCharCode) ||
|
|
|
|
key->GetAttr(kNameSpaceID_None, nsGkAtoms::keycode, valKeyCode);
|
|
|
|
if (attrExists &&
|
|
|
|
valKey.IsEmpty() && valCharCode.IsEmpty() && valKeyCode.IsEmpty())
|
2008-04-14 21:16:24 -07:00
|
|
|
continue;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsXBLPrototypeHandler* handler = new nsXBLPrototypeHandler(key);
|
|
|
|
|
|
|
|
if (!handler)
|
|
|
|
return;
|
|
|
|
|
|
|
|
handler->SetNextHandler(*aResult);
|
|
|
|
*aResult = handler;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// EnsureHandlers
|
|
|
|
//
|
|
|
|
// Lazily load the XBL handlers. Overridden to handle being attached
|
|
|
|
// to a particular element rather than the document
|
|
|
|
//
|
|
|
|
nsresult
|
2014-01-22 19:18:51 -08:00
|
|
|
nsXBLWindowKeyHandler::EnsureHandlers()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-04-14 11:27:33 -07:00
|
|
|
nsCOMPtr<Element> el = GetElement();
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_STATE(!mWeakPtrForElement || el);
|
|
|
|
if (el) {
|
|
|
|
// We are actually a XUL <keyset>.
|
|
|
|
if (mHandler)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(el));
|
|
|
|
BuildHandlerChain(content, &mHandler);
|
|
|
|
} else { // We are an XBL file of handlers.
|
|
|
|
if (!sXBLSpecialDocInfo) {
|
2012-10-14 09:15:12 -07:00
|
|
|
sXBLSpecialDocInfo = new nsXBLSpecialDocInfo();
|
|
|
|
NS_ADDREF(sXBLSpecialDocInfo);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
sXBLSpecialDocInfo->LoadDocInfo();
|
|
|
|
|
|
|
|
// Now determine which handlers we should be using.
|
2014-01-22 19:18:51 -08:00
|
|
|
if (IsHTMLEditableFieldFocused()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
sXBLSpecialDocInfo->GetAllHandlers("editor", &mHandler, &mUserHandler);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sXBLSpecialDocInfo->GetAllHandlers("browser", &mHandler, &mUserHandler);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2008-09-15 18:37:13 -07:00
|
|
|
nsXBLWindowKeyHandler::WalkHandlers(nsIDOMKeyEvent* aKeyEvent, nsIAtom* aEventType)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-28 23:19:26 -07:00
|
|
|
bool prevent;
|
2013-05-25 14:05:36 -07:00
|
|
|
aKeyEvent->GetDefaultPrevented(&prevent);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (prevent)
|
|
|
|
return NS_OK;
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool trustedEvent = false;
|
2012-08-04 00:44:00 -07:00
|
|
|
// Don't process the event if it was not dispatched from a trusted source
|
|
|
|
aKeyEvent->GetIsTrusted(&trustedEvent);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (!trustedEvent)
|
|
|
|
return NS_OK;
|
|
|
|
|
2014-01-22 19:18:51 -08:00
|
|
|
nsresult rv = EnsureHandlers();
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2013-04-14 11:27:33 -07:00
|
|
|
|
2014-03-18 08:16:47 -07:00
|
|
|
bool isDisabled;
|
|
|
|
nsCOMPtr<Element> el = GetElement(&isDisabled);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!el) {
|
|
|
|
if (mUserHandler) {
|
2014-03-18 08:16:47 -07:00
|
|
|
WalkHandlersInternal(aKeyEvent, aEventType, mUserHandler, true);
|
2013-05-25 14:05:36 -07:00
|
|
|
aKeyEvent->GetDefaultPrevented(&prevent);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (prevent)
|
|
|
|
return NS_OK; // Handled by the user bindings. Our work here is done.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-06 07:32:09 -07:00
|
|
|
// skip keysets that are disabled
|
2014-03-18 08:16:47 -07:00
|
|
|
if (el && isDisabled) {
|
2008-08-06 07:32:09 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-03-18 08:16:47 -07:00
|
|
|
WalkHandlersInternal(aKeyEvent, aEventType, mHandler, true);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-06-24 16:12:34 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLWindowKeyHandler::HandleEvent(nsIDOMEvent* aEvent)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-09-15 18:37:13 -07:00
|
|
|
nsCOMPtr<nsIDOMKeyEvent> keyEvent(do_QueryInterface(aEvent));
|
|
|
|
NS_ENSURE_TRUE(keyEvent, NS_ERROR_INVALID_ARG);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2014-03-18 08:16:47 -07:00
|
|
|
uint16_t eventPhase;
|
|
|
|
aEvent->GetEventPhase(&eventPhase);
|
|
|
|
if (eventPhase == nsIDOMEvent::CAPTURING_PHASE) {
|
|
|
|
HandleEventOnCapture(keyEvent);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-06-24 16:12:34 -07:00
|
|
|
nsAutoString eventType;
|
|
|
|
aEvent->GetType(eventType);
|
|
|
|
nsCOMPtr<nsIAtom> eventTypeAtom = do_GetAtom(eventType);
|
|
|
|
NS_ENSURE_TRUE(eventTypeAtom, NS_ERROR_OUT_OF_MEMORY);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2014-03-18 08:16:47 -07:00
|
|
|
return WalkHandlers(keyEvent, eventTypeAtom);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsXBLWindowKeyHandler::HandleEventOnCapture(nsIDOMKeyEvent* aEvent)
|
|
|
|
{
|
|
|
|
WidgetKeyboardEvent* widgetEvent =
|
|
|
|
aEvent->GetInternalNSEvent()->AsKeyboardEvent();
|
|
|
|
|
|
|
|
if (widgetEvent->mFlags.mNoCrossProcessBoundaryForwarding) {
|
|
|
|
return;
|
2013-01-24 08:38:59 -08:00
|
|
|
}
|
|
|
|
|
2014-03-18 08:16:47 -07:00
|
|
|
nsCOMPtr<mozilla::dom::Element> originalTarget =
|
|
|
|
do_QueryInterface(aEvent->GetInternalNSEvent()->originalTarget);
|
2014-03-31 21:09:23 -07:00
|
|
|
if (!EventStateManager::IsRemoteTarget(originalTarget)) {
|
2014-03-18 08:16:47 -07:00
|
|
|
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();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// EventMatched
|
|
|
|
//
|
|
|
|
// See if the given handler cares about this particular key event
|
|
|
|
//
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2014-12-12 04:17:37 -08:00
|
|
|
nsXBLWindowKeyHandler::EventMatched(
|
|
|
|
nsXBLPrototypeHandler* aHandler,
|
|
|
|
nsIAtom* aEventType,
|
|
|
|
nsIDOMKeyEvent* aEvent,
|
|
|
|
uint32_t aCharCode,
|
|
|
|
const IgnoreModifierState& aIgnoreModifierState)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2014-12-12 04:17:37 -08:00
|
|
|
return aHandler->KeyEventMatched(aEventType, aEvent, aCharCode,
|
|
|
|
aIgnoreModifierState);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2014-01-22 19:18:51 -08:00
|
|
|
nsXBLWindowKeyHandler::IsHTMLEditableFieldFocused()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
|
|
if (!fm)
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
nsCOMPtr<nsIDOMWindow> focusedWindow;
|
|
|
|
fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!focusedWindow)
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsPIDOMWindow> piwin(do_QueryInterface(focusedWindow));
|
|
|
|
nsIDocShell *docShell = piwin->GetDocShell();
|
2014-01-22 19:18:51 -08:00
|
|
|
if (!docShell) {
|
|
|
|
return false;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2014-01-22 19:18:51 -08:00
|
|
|
nsCOMPtr<nsIEditor> editor;
|
|
|
|
docShell->GetEditor(getter_AddRefs(editor));
|
|
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
|
|
|
|
if (!htmlEditor) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-02-10 11:55:01 -08:00
|
|
|
nsCOMPtr<nsIDOMDocument> domDocument;
|
|
|
|
editor->GetDocument(getter_AddRefs(domDocument));
|
|
|
|
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDocument);
|
|
|
|
if (doc->HasFlag(NODE_IS_EDITABLE)) {
|
|
|
|
// Don't need to perform any checks in designMode documents.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-01-22 19:18:51 -08:00
|
|
|
nsCOMPtr<nsIDOMElement> focusedElement;
|
|
|
|
fm->GetFocusedElement(getter_AddRefs(focusedElement));
|
|
|
|
nsCOMPtr<nsINode> focusedNode = do_QueryInterface(focusedElement);
|
|
|
|
if (focusedNode) {
|
|
|
|
// If there is a focused element, make sure it's in the active editing host.
|
|
|
|
// Note that GetActiveEditingHost finds the current editing host based on
|
|
|
|
// the document's selection. Even though the document selection is usually
|
|
|
|
// collapsed to where the focus is, but the page may modify the selection
|
|
|
|
// without our knowledge, in which case this check will do something useful.
|
|
|
|
nsCOMPtr<Element> activeEditingHost = htmlEditor->GetActiveEditingHost();
|
|
|
|
if (!activeEditingHost) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return nsContentUtils::ContentIsDescendantOf(focusedNode, activeEditingHost);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
2008-04-14 21:16:24 -07:00
|
|
|
// WalkHandlersInternal and WalkHandlersAndExecute
|
2007-03-22 10:30:00 -07:00
|
|
|
//
|
|
|
|
// Given a particular DOM event and a pointer to the first handler in the list,
|
2014-03-18 08:16:47 -07:00
|
|
|
// 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.
|
2007-03-22 10:30:00 -07:00
|
|
|
//
|
2014-03-18 08:16:47 -07:00
|
|
|
bool
|
2008-09-15 18:37:13 -07:00
|
|
|
nsXBLWindowKeyHandler::WalkHandlersInternal(nsIDOMKeyEvent* aKeyEvent,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIAtom* aEventType,
|
2014-03-18 08:16:47 -07:00
|
|
|
nsXBLPrototypeHandler* aHandler,
|
|
|
|
bool aExecute)
|
2008-04-14 21:16:24 -07:00
|
|
|
{
|
|
|
|
nsAutoTArray<nsShortcutCandidate, 10> accessKeys;
|
2008-09-15 18:37:13 -07:00
|
|
|
nsContentUtils::GetAccelKeyCandidates(aKeyEvent, accessKeys);
|
2008-04-14 21:16:24 -07:00
|
|
|
|
|
|
|
if (accessKeys.IsEmpty()) {
|
2014-03-18 08:16:47 -07:00
|
|
|
return WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler,
|
2014-12-12 04:17:37 -08:00
|
|
|
0, IgnoreModifierState(), aExecute);
|
2008-04-14 21:16:24 -07:00
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
for (uint32_t i = 0; i < accessKeys.Length(); ++i) {
|
2008-04-14 21:16:24 -07:00
|
|
|
nsShortcutCandidate &key = accessKeys[i];
|
2014-12-12 04:17:37 -08:00
|
|
|
IgnoreModifierState ignoreModifierState;
|
|
|
|
ignoreModifierState.mShift = key.mIgnoreShift;
|
2008-09-15 18:37:13 -07:00
|
|
|
if (WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler,
|
2014-12-12 04:17:37 -08:00
|
|
|
key.mCharCode, ignoreModifierState, aExecute)) {
|
2014-03-18 08:16:47 -07:00
|
|
|
return true;
|
2014-12-12 04:17:37 -08:00
|
|
|
}
|
2008-04-14 21:16:24 -07:00
|
|
|
}
|
2014-03-18 08:16:47 -07:00
|
|
|
return false;
|
2008-04-14 21:16:24 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2014-12-12 04:17:37 -08:00
|
|
|
nsXBLWindowKeyHandler::WalkHandlersAndExecute(
|
|
|
|
nsIDOMKeyEvent* aKeyEvent,
|
|
|
|
nsIAtom* aEventType,
|
|
|
|
nsXBLPrototypeHandler* aHandler,
|
|
|
|
uint32_t aCharCode,
|
|
|
|
const IgnoreModifierState& aIgnoreModifierState,
|
|
|
|
bool aExecute)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
nsresult rv;
|
2008-04-14 21:16:24 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Try all of the handlers until we find one that matches the event.
|
|
|
|
for (nsXBLPrototypeHandler *currHandler = aHandler; currHandler;
|
|
|
|
currHandler = currHandler->GetNextHandler()) {
|
2012-06-10 16:44:50 -07:00
|
|
|
bool stopped = aKeyEvent->IsDispatchStopped();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (stopped) {
|
|
|
|
// The event is finished, don't execute any more handlers
|
2012-08-07 08:11:35 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-09-15 18:37:13 -07:00
|
|
|
if (!EventMatched(currHandler, aEventType, aKeyEvent,
|
2014-12-12 04:17:37 -08:00
|
|
|
aCharCode, aIgnoreModifierState)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
continue; // try the next one
|
2014-12-12 04:17:37 -08:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// 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();
|
2013-04-14 11:27:33 -07:00
|
|
|
nsCOMPtr<Element> commandElt;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// See if we're in a XUL doc.
|
2013-04-14 11:27:33 -07:00
|
|
|
nsCOMPtr<Element> el = GetElement();
|
2007-03-22 10:30:00 -07:00
|
|
|
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");
|
2010-06-23 14:35:57 -07:00
|
|
|
nsIDocument *doc = elt->GetCurrentDoc();
|
|
|
|
if (doc)
|
|
|
|
commandElt = do_QueryInterface(doc->GetElementById(command));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (!commandElt) {
|
2010-06-17 13:28:38 -07:00
|
|
|
NS_ERROR("A XUL <key> is observing a command that doesn't exist. Unable to execute key binding!");
|
2007-03-22 10:30:00 -07:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 17:44:26 -07:00
|
|
|
nsCOMPtr<EventTarget> piTarget;
|
2013-04-14 11:27:33 -07:00
|
|
|
nsCOMPtr<Element> element = GetElement();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (element) {
|
2013-04-14 11:27:33 -07:00
|
|
|
piTarget = commandElt;
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
2013-04-14 11:27:33 -07:00
|
|
|
piTarget = mTarget;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2014-03-18 08:16:47 -07:00
|
|
|
if (!aExecute) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-09-15 18:37:13 -07:00
|
|
|
rv = currHandler->ExecuteHandler(piTarget, aKeyEvent);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-12 04:17:37 -08:00
|
|
|
#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->GetInternalNSEvent()->AsKeyboardEvent();
|
|
|
|
if (keyEvent && keyEvent->IsOS()) {
|
|
|
|
IgnoreModifierState ignoreModifierState(aIgnoreModifierState);
|
|
|
|
ignoreModifierState.mOS = true;
|
|
|
|
return WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler, aCharCode,
|
|
|
|
ignoreModifierState, aExecute);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2014-03-18 08:16:47 -07:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-04-14 11:27:33 -07:00
|
|
|
already_AddRefed<Element>
|
2014-03-18 08:16:47 -07:00
|
|
|
nsXBLWindowKeyHandler::GetElement(bool* aIsDisabled)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-04-14 11:27:33 -07:00
|
|
|
nsCOMPtr<Element> element = do_QueryReferent(mWeakPtrForElement);
|
2014-03-18 08:16:47 -07:00
|
|
|
if (element && aIsDisabled) {
|
|
|
|
*aIsDisabled = element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
|
|
|
|
nsGkAtoms::_true, eCaseMatters);
|
|
|
|
}
|
2013-04-14 11:27:33 -07:00
|
|
|
return element.forget();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2013-04-14 11:27:33 -07:00
|
|
|
already_AddRefed<nsXBLWindowKeyHandler>
|
|
|
|
NS_NewXBLWindowKeyHandler(nsIDOMElement* aElement, EventTarget* aTarget)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2013-04-14 11:27:33 -07:00
|
|
|
nsRefPtr<nsXBLWindowKeyHandler> result =
|
|
|
|
new nsXBLWindowKeyHandler(aElement, aTarget);
|
|
|
|
return result.forget();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|