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"
|
2007-05-14 02:11:38 -07:00
|
|
|
#include "nsIDOMEventTarget.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIDOMNSEvent.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"
|
|
|
|
#include "nsINativeKeyBindings.h"
|
|
|
|
#include "nsIController.h"
|
|
|
|
#include "nsIControllers.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 "nsPIWindowRoot.h"
|
|
|
|
#include "nsIURI.h"
|
|
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "nsContentUtils.h"
|
|
|
|
#include "nsXBLPrototypeBinding.h"
|
|
|
|
#include "nsIDOMDocument.h"
|
|
|
|
#include "nsPIDOMWindow.h"
|
|
|
|
#include "nsIDocShell.h"
|
|
|
|
#include "nsIPresShell.h"
|
2012-06-10 16:37:47 -07:00
|
|
|
#include "nsIPrivateDOMEvent.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsISelectionController.h"
|
2008-04-14 21:16:24 -07:00
|
|
|
#include "nsGUIEvent.h"
|
2011-05-28 00:03:00 -07:00
|
|
|
#include "mozilla/Preferences.h"
|
2011-07-20 12:18:54 -07:00
|
|
|
#include "mozilla/dom/Element.h"
|
2011-05-28 00:03:00 -07:00
|
|
|
|
|
|
|
using namespace mozilla;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
static nsINativeKeyBindings *sNativeEditorBindings = nsnull;
|
|
|
|
|
|
|
|
class nsXBLSpecialDocInfo
|
|
|
|
{
|
|
|
|
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:
|
|
|
|
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) {}
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
const char nsXBLSpecialDocInfo::sHTMLBindingStr[] =
|
|
|
|
"chrome://global/content/platformHTMLBindings.xml";
|
|
|
|
|
|
|
|
void nsXBLSpecialDocInfo::LoadDocInfo()
|
|
|
|
{
|
|
|
|
if (mInitialized)
|
|
|
|
return;
|
2011-10-17 07:59:28 -07:00
|
|
|
mInitialized = true;
|
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;
|
|
|
|
}
|
|
|
|
xblService->LoadBindingDocumentInfo(nsnull, nsnull,
|
|
|
|
bindingURI,
|
2007-07-18 14:56:57 -07:00
|
|
|
nsnull,
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
xblService->LoadBindingDocumentInfo(nsnull, nsnull,
|
|
|
|
bindingURI,
|
2007-07-18 14:56:57 -07:00
|
|
|
nsnull,
|
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) {
|
|
|
|
nsCAutoString type(aType);
|
|
|
|
type.Append("User");
|
|
|
|
GetHandlers(mUserHTMLBindings, type, aUserHandler);
|
|
|
|
}
|
|
|
|
if (mHTMLBindings) {
|
|
|
|
GetHandlers(mHTMLBindings, nsDependentCString(aType), aHandler);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Init statics
|
|
|
|
nsXBLSpecialDocInfo* nsXBLWindowKeyHandler::sXBLSpecialDocInfo = nsnull;
|
|
|
|
PRUint32 nsXBLWindowKeyHandler::sRefCnt = 0;
|
|
|
|
|
2007-05-14 02:11:38 -07:00
|
|
|
nsXBLWindowKeyHandler::nsXBLWindowKeyHandler(nsIDOMElement* aElement,
|
2011-06-23 19:18:00 -07:00
|
|
|
nsIDOMEventTarget* aTarget)
|
2007-05-14 02:11:38 -07:00
|
|
|
: mTarget(aTarget),
|
2007-03-22 10:30:00 -07:00
|
|
|
mHandler(nsnull),
|
|
|
|
mUserHandler(nsnull)
|
|
|
|
{
|
|
|
|
mWeakPtrForElement = do_GetWeakReference(aElement);
|
|
|
|
++sRefCnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsXBLWindowKeyHandler::~nsXBLWindowKeyHandler()
|
|
|
|
{
|
|
|
|
// If mWeakPtrForElement is non-null, we created a prototype handler.
|
|
|
|
if (mWeakPtrForElement)
|
|
|
|
delete mHandler;
|
|
|
|
|
|
|
|
--sRefCnt;
|
|
|
|
if (!sRefCnt) {
|
|
|
|
delete sXBLSpecialDocInfo;
|
|
|
|
sXBLSpecialDocInfo = nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-24 16:12:34 -07:00
|
|
|
NS_IMPL_ISUPPORTS1(nsXBLWindowKeyHandler,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIDOMEventListener)
|
|
|
|
|
|
|
|
static void
|
|
|
|
BuildHandlerChain(nsIContent* aContent, nsXBLPrototypeHandler** aResult)
|
|
|
|
{
|
|
|
|
*aResult = nsnull;
|
|
|
|
|
|
|
|
// 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
|
2011-09-28 23:19:26 -07:00
|
|
|
nsXBLWindowKeyHandler::EnsureHandlers(bool *aIsEditor)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMElement> el = GetElement();
|
|
|
|
NS_ENSURE_STATE(!mWeakPtrForElement || el);
|
|
|
|
if (el) {
|
|
|
|
// We are actually a XUL <keyset>.
|
|
|
|
if (aIsEditor)
|
2011-10-17 07:59:28 -07:00
|
|
|
*aIsEditor = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (mHandler)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(el));
|
|
|
|
BuildHandlerChain(content, &mHandler);
|
|
|
|
} else { // We are an XBL file of handlers.
|
|
|
|
if (!sXBLSpecialDocInfo)
|
|
|
|
sXBLSpecialDocInfo = new nsXBLSpecialDocInfo();
|
|
|
|
if (!sXBLSpecialDocInfo) {
|
|
|
|
if (aIsEditor) {
|
2011-10-17 07:59:28 -07:00
|
|
|
*aIsEditor = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
sXBLSpecialDocInfo->LoadDocInfo();
|
|
|
|
|
|
|
|
// Now determine which handlers we should be using.
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isEditor = IsEditor();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (isEditor) {
|
|
|
|
sXBLSpecialDocInfo->GetAllHandlers("editor", &mHandler, &mUserHandler);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sXBLSpecialDocInfo->GetAllHandlers("browser", &mHandler, &mUserHandler);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aIsEditor)
|
|
|
|
*aIsEditor = isEditor;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static nsINativeKeyBindings*
|
|
|
|
GetEditorKeyBindings()
|
|
|
|
{
|
2011-09-28 23:19:26 -07:00
|
|
|
static bool noBindings = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!sNativeEditorBindings && !noBindings) {
|
|
|
|
CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "editor",
|
|
|
|
&sNativeEditorBindings);
|
|
|
|
|
|
|
|
if (!sNativeEditorBindings) {
|
2011-10-17 07:59:28 -07:00
|
|
|
noBindings = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return sNativeEditorBindings;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
DoCommandCallback(const char *aCommand, void *aData)
|
|
|
|
{
|
2007-07-08 00:08:04 -07:00
|
|
|
nsIControllers *controllers = static_cast<nsIControllers*>(aData);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (controllers) {
|
|
|
|
nsCOMPtr<nsIController> controller;
|
|
|
|
controllers->GetControllerForCommand(aCommand, getter_AddRefs(controller));
|
|
|
|
if (controller) {
|
|
|
|
controller->DoCommand(aCommand);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2008-09-15 18:37:13 -07:00
|
|
|
nsXBLWindowKeyHandler::WalkHandlers(nsIDOMKeyEvent* aKeyEvent, nsIAtom* aEventType)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-08-26 00:43:49 -07:00
|
|
|
nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aKeyEvent);
|
2011-09-28 23:19:26 -07:00
|
|
|
bool prevent;
|
2011-08-26 00:43:49 -07:00
|
|
|
domNSEvent->GetPreventDefault(&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;
|
2007-03-22 10:30:00 -07:00
|
|
|
if (domNSEvent) {
|
|
|
|
//Don't process the event if it was not dispatched from a trusted source
|
|
|
|
domNSEvent->GetIsTrusted(&trustedEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!trustedEvent)
|
|
|
|
return NS_OK;
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isEditor;
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult rv = EnsureHandlers(&isEditor);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMElement> el = GetElement();
|
|
|
|
if (!el) {
|
|
|
|
if (mUserHandler) {
|
|
|
|
WalkHandlersInternal(aKeyEvent, aEventType, mUserHandler);
|
2011-08-26 00:43:49 -07:00
|
|
|
domNSEvent->GetPreventDefault(&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
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(el);
|
|
|
|
// skip keysets that are disabled
|
|
|
|
if (content && content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
|
|
|
|
nsGkAtoms::_true, eCaseMatters)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
WalkHandlersInternal(aKeyEvent, aEventType, mHandler);
|
|
|
|
|
2009-07-22 15:31:01 -07:00
|
|
|
if (isEditor && GetEditorKeyBindings()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
nsNativeKeyEvent nativeEvent;
|
|
|
|
// get the DOM window we're attached to
|
|
|
|
nsCOMPtr<nsIControllers> controllers;
|
2007-05-14 02:11:38 -07:00
|
|
|
nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(mTarget);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (root) {
|
2010-02-20 08:07:03 -08:00
|
|
|
root->GetControllers(getter_AddRefs(controllers));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool handled = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aEventType == nsGkAtoms::keypress) {
|
2011-10-17 07:59:28 -07:00
|
|
|
if (nsContentUtils::DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent, true))
|
2008-10-15 03:50:42 -07:00
|
|
|
handled = sNativeEditorBindings->KeyPress(nativeEvent,
|
|
|
|
DoCommandCallback, controllers);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else if (aEventType == nsGkAtoms::keyup) {
|
2011-10-17 07:59:28 -07:00
|
|
|
if (nsContentUtils::DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent, false))
|
2008-10-15 03:50:42 -07:00
|
|
|
handled = sNativeEditorBindings->KeyUp(nativeEvent,
|
2007-03-22 10:30:00 -07:00
|
|
|
DoCommandCallback, controllers);
|
2008-10-15 03:50:42 -07:00
|
|
|
} else {
|
|
|
|
NS_ASSERTION(aEventType == nsGkAtoms::keydown, "unknown key event type");
|
2011-10-17 07:59:28 -07:00
|
|
|
if (nsContentUtils::DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent, false))
|
2008-10-15 03:50:42 -07:00
|
|
|
handled = sNativeEditorBindings->KeyDown(nativeEvent,
|
|
|
|
DoCommandCallback, controllers);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (handled)
|
|
|
|
aKeyEvent->PreventDefault();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
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
|
|
|
|
2011-06-24 16:12:34 -07:00
|
|
|
return WalkHandlers(keyEvent, eventTypeAtom);
|
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
|
2007-03-22 10:30:00 -07:00
|
|
|
nsXBLWindowKeyHandler::EventMatched(nsXBLPrototypeHandler* inHandler,
|
2008-09-15 18:37:13 -07:00
|
|
|
nsIAtom* inEventType,
|
|
|
|
nsIDOMKeyEvent* inEvent,
|
2011-09-28 23:19:26 -07:00
|
|
|
PRUint32 aCharCode, bool aIgnoreShiftKey)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-09-15 18:37:13 -07:00
|
|
|
return inHandler->KeyEventMatched(inEventType, inEvent, aCharCode,
|
|
|
|
aIgnoreShiftKey);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ void
|
|
|
|
nsXBLWindowKeyHandler::ShutDown()
|
|
|
|
{
|
|
|
|
NS_IF_RELEASE(sNativeEditorBindings);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// IsEditor
|
|
|
|
//
|
|
|
|
// Determine if the document we're working with is Editor or Browser
|
|
|
|
//
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2007-03-22 10:30:00 -07:00
|
|
|
nsXBLWindowKeyHandler::IsEditor()
|
|
|
|
{
|
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
|
|
|
// XXXndeakin even though this is only used for key events which should be
|
|
|
|
// going to the focused frame anyway, this doesn't seem like the right way
|
|
|
|
// to determine if something is an editor.
|
|
|
|
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();
|
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
|
|
if (docShell)
|
|
|
|
docShell->GetPresShell(getter_AddRefs(presShell));
|
|
|
|
|
|
|
|
if (presShell) {
|
2010-03-20 14:54:19 -07:00
|
|
|
return presShell->GetSelectionFlags() == nsISelectionDisplay::DISPLAY_ALL;
|
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,
|
|
|
|
// scan through the list to find something to handle the event and then make it
|
|
|
|
// so.
|
|
|
|
//
|
|
|
|
nsresult
|
2008-09-15 18:37:13 -07:00
|
|
|
nsXBLWindowKeyHandler::WalkHandlersInternal(nsIDOMKeyEvent* aKeyEvent,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIAtom* aEventType,
|
|
|
|
nsXBLPrototypeHandler* aHandler)
|
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()) {
|
2011-10-17 07:59:28 -07:00
|
|
|
WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler, 0, false);
|
2008-04-14 21:16:24 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (PRUint32 i = 0; i < accessKeys.Length(); ++i) {
|
|
|
|
nsShortcutCandidate &key = accessKeys[i];
|
2008-09-15 18:37:13 -07:00
|
|
|
if (WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler,
|
2008-04-14 21:16:24 -07:00
|
|
|
key.mCharCode, key.mIgnoreShift))
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2008-09-15 18:37:13 -07:00
|
|
|
nsXBLWindowKeyHandler::WalkHandlersAndExecute(nsIDOMKeyEvent* aKeyEvent,
|
2008-04-14 21:16:24 -07:00
|
|
|
nsIAtom* aEventType,
|
|
|
|
nsXBLPrototypeHandler* aHandler,
|
|
|
|
PRUint32 aCharCode,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aIgnoreShiftKey)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
nsresult rv;
|
2012-06-10 16:37:47 -07:00
|
|
|
nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aKeyEvent));
|
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:37:47 -07:00
|
|
|
bool stopped = privateEvent->IsDispatchStopped();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (stopped) {
|
|
|
|
// The event is finished, don't execute any more handlers
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-09-15 18:37:13 -07:00
|
|
|
if (!EventMatched(currHandler, aEventType, aKeyEvent,
|
2008-04-14 21:16:24 -07:00
|
|
|
aCharCode, aIgnoreShiftKey))
|
2007-03-22 10:30:00 -07:00
|
|
|
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<nsIDOMElement> commandElt;
|
|
|
|
|
|
|
|
// See if we're in a XUL doc.
|
|
|
|
nsCOMPtr<nsIDOMElement> 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");
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-23 19:18:00 -07:00
|
|
|
nsCOMPtr<nsIDOMEventTarget> piTarget;
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDOMElement> element = GetElement();
|
|
|
|
if (element) {
|
2007-05-14 02:11:38 -07:00
|
|
|
piTarget = do_QueryInterface(commandElt);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
2007-05-14 02:11:38 -07:00
|
|
|
piTarget = mTarget;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<nsIDOMElement>
|
|
|
|
nsXBLWindowKeyHandler::GetElement()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMElement> element = do_QueryReferent(mWeakPtrForElement);
|
|
|
|
nsIDOMElement* el = nsnull;
|
|
|
|
element.swap(el);
|
|
|
|
return el;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
nsresult
|
2011-06-23 19:18:00 -07:00
|
|
|
NS_NewXBLWindowKeyHandler(nsIDOMElement* aElement, nsIDOMEventTarget* aTarget,
|
2007-05-14 02:11:38 -07:00
|
|
|
nsXBLWindowKeyHandler** aResult)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-05-14 02:11:38 -07:00
|
|
|
*aResult = new nsXBLWindowKeyHandler(aElement, aTarget);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!*aResult)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
NS_ADDREF(*aResult);
|
|
|
|
return NS_OK;
|
|
|
|
}
|