2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is Mozilla Communicator client code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
|
|
|
* - Mike Pinkerton (pinkerton@netscape.com)
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsXBLPrototypeHandler.h"
|
|
|
|
#include "nsXBLWindowKeyHandler.h"
|
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIAtom.h"
|
|
|
|
#include "nsIDOMNSUIEvent.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"
|
|
|
|
#include "nsIXBLDocumentInfo.h"
|
|
|
|
#include "nsIDOMElement.h"
|
|
|
|
#include "nsINativeKeyBindings.h"
|
|
|
|
#include "nsIController.h"
|
|
|
|
#include "nsIControllers.h"
|
|
|
|
#include "nsIDOMWindowInternal.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 "nsIDOMNSDocument.h"
|
|
|
|
#include "nsPIWindowRoot.h"
|
|
|
|
#include "nsPIDOMWindow.h"
|
|
|
|
#include "nsIDocShell.h"
|
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsIPrivateDOMEvent.h"
|
|
|
|
#include "nsISelectionController.h"
|
2008-04-14 21:16:24 -07:00
|
|
|
#include "nsGUIEvent.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
static nsINativeKeyBindings *sNativeEditorBindings = nsnull;
|
|
|
|
|
|
|
|
class nsXBLSpecialDocInfo
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
nsCOMPtr<nsIXBLDocumentInfo> mHTMLBindings;
|
|
|
|
nsCOMPtr<nsIXBLDocumentInfo> mUserHTMLBindings;
|
|
|
|
|
|
|
|
static const char sHTMLBindingStr[];
|
|
|
|
static const char sUserHTMLBindingStr[];
|
|
|
|
|
|
|
|
PRBool mInitialized;
|
|
|
|
|
|
|
|
public:
|
|
|
|
void LoadDocInfo();
|
|
|
|
void GetAllHandlers(const char* aType,
|
|
|
|
nsXBLPrototypeHandler** handler,
|
|
|
|
nsXBLPrototypeHandler** userHandler);
|
|
|
|
void GetHandlers(nsIXBLDocumentInfo* aInfo,
|
|
|
|
const nsACString& aRef,
|
|
|
|
nsXBLPrototypeHandler** aResult);
|
|
|
|
|
2007-04-23 07:21:53 -07:00
|
|
|
nsXBLSpecialDocInfo() : mInitialized(PR_FALSE) {}
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
const char nsXBLSpecialDocInfo::sHTMLBindingStr[] =
|
|
|
|
"chrome://global/content/platformHTMLBindings.xml";
|
|
|
|
|
|
|
|
void nsXBLSpecialDocInfo::LoadDocInfo()
|
|
|
|
{
|
|
|
|
if (mInitialized)
|
|
|
|
return;
|
|
|
|
mInitialized = PR_TRUE;
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIXBLService> xblService =
|
|
|
|
do_GetService("@mozilla.org/xbl;1", &rv);
|
|
|
|
if (NS_FAILED(rv) || !xblService)
|
|
|
|
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,
|
2007-03-22 10:30:00 -07:00
|
|
|
PR_TRUE,
|
|
|
|
getter_AddRefs(mHTMLBindings));
|
|
|
|
|
|
|
|
const nsAdoptingCString& userHTMLBindingStr =
|
|
|
|
nsContentUtils::GetCharPref("dom.userHTMLBindings.uri");
|
|
|
|
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,
|
2007-03-22 10:30:00 -07:00
|
|
|
PR_TRUE,
|
|
|
|
getter_AddRefs(mUserHTMLBindings));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// GetHandlers
|
|
|
|
//
|
|
|
|
//
|
|
|
|
void
|
|
|
|
nsXBLSpecialDocInfo::GetHandlers(nsIXBLDocumentInfo* aInfo,
|
|
|
|
const nsACString& aRef,
|
|
|
|
nsXBLPrototypeHandler** aResult)
|
|
|
|
{
|
|
|
|
nsXBLPrototypeBinding* binding;
|
|
|
|
aInfo->GetPrototypeBinding(aRef, &binding);
|
|
|
|
|
|
|
|
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,
|
|
|
|
nsPIDOMEventTarget* aTarget)
|
|
|
|
: 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS2(nsXBLWindowKeyHandler,
|
|
|
|
nsIDOMKeyListener,
|
|
|
|
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
|
|
|
|
for (PRUint32 j = aContent->GetChildCount(); j--; ) {
|
|
|
|
nsIContent *key = aContent->GetChildAt(j);
|
|
|
|
|
|
|
|
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;
|
2008-04-14 21:16:24 -07:00
|
|
|
PRBool 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
|
|
|
|
nsXBLWindowKeyHandler::EnsureHandlers(PRBool *aIsEditor)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMElement> el = GetElement();
|
|
|
|
NS_ENSURE_STATE(!mWeakPtrForElement || el);
|
|
|
|
if (el) {
|
|
|
|
// We are actually a XUL <keyset>.
|
|
|
|
if (aIsEditor)
|
|
|
|
*aIsEditor = PR_FALSE;
|
|
|
|
|
|
|
|
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) {
|
|
|
|
*aIsEditor = PR_FALSE;
|
|
|
|
}
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
sXBLSpecialDocInfo->LoadDocInfo();
|
|
|
|
|
|
|
|
// Now determine which handlers we should be using.
|
|
|
|
PRBool isEditor = IsEditor();
|
|
|
|
if (isEditor) {
|
|
|
|
sXBLSpecialDocInfo->GetAllHandlers("editor", &mHandler, &mUserHandler);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sXBLSpecialDocInfo->GetAllHandlers("browser", &mHandler, &mUserHandler);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aIsEditor)
|
|
|
|
*aIsEditor = isEditor;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static nsINativeKeyBindings*
|
|
|
|
GetEditorKeyBindings()
|
|
|
|
{
|
|
|
|
static PRBool noBindings = PR_FALSE;
|
|
|
|
if (!sNativeEditorBindings && !noBindings) {
|
|
|
|
CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "editor",
|
|
|
|
&sNativeEditorBindings);
|
|
|
|
|
|
|
|
if (!sNativeEditorBindings) {
|
|
|
|
noBindings = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNSUIEvent> evt = do_QueryInterface(aKeyEvent);
|
|
|
|
PRBool prevent;
|
|
|
|
evt->GetPreventDefault(&prevent);
|
|
|
|
if (prevent)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aKeyEvent);
|
|
|
|
PRBool trustedEvent = PR_FALSE;
|
|
|
|
|
|
|
|
if (domNSEvent) {
|
|
|
|
//Don't process the event if it was not dispatched from a trusted source
|
|
|
|
domNSEvent->GetIsTrusted(&trustedEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!trustedEvent)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
PRBool isEditor;
|
|
|
|
nsresult rv = EnsureHandlers(&isEditor);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMElement> el = GetElement();
|
|
|
|
if (!el) {
|
|
|
|
if (mUserHandler) {
|
|
|
|
WalkHandlersInternal(aKeyEvent, aEventType, mUserHandler);
|
|
|
|
evt->GetPreventDefault(&prevent);
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2008-10-15 03:50:42 -07:00
|
|
|
PRBool handled = PR_FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aEventType == nsGkAtoms::keypress) {
|
2008-10-15 03:50:42 -07:00
|
|
|
if (nsContentUtils::DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent, PR_TRUE))
|
|
|
|
handled = sNativeEditorBindings->KeyPress(nativeEvent,
|
|
|
|
DoCommandCallback, controllers);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else if (aEventType == nsGkAtoms::keyup) {
|
2008-10-15 03:50:42 -07:00
|
|
|
if (nsContentUtils::DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent, PR_FALSE))
|
|
|
|
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");
|
|
|
|
if (nsContentUtils::DOMEventToNativeKeyEvent(aKeyEvent, &nativeEvent, PR_FALSE))
|
|
|
|
handled = sNativeEditorBindings->KeyDown(nativeEvent,
|
|
|
|
DoCommandCallback, controllers);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (handled)
|
|
|
|
aKeyEvent->PreventDefault();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-09-15 18:37:13 -07:00
|
|
|
nsresult nsXBLWindowKeyHandler::KeyUp(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);
|
|
|
|
return WalkHandlers(keyEvent, nsGkAtoms::keyup);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-09-15 18:37:13 -07:00
|
|
|
nsresult nsXBLWindowKeyHandler::KeyDown(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);
|
|
|
|
return WalkHandlers(keyEvent, nsGkAtoms::keydown);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-09-15 18:37:13 -07:00
|
|
|
nsresult nsXBLWindowKeyHandler::KeyPress(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);
|
|
|
|
return WalkHandlers(keyEvent, nsGkAtoms::keypress);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// EventMatched
|
|
|
|
//
|
|
|
|
// See if the given handler cares about this particular key event
|
|
|
|
//
|
|
|
|
PRBool
|
|
|
|
nsXBLWindowKeyHandler::EventMatched(nsXBLPrototypeHandler* inHandler,
|
2008-09-15 18:37:13 -07:00
|
|
|
nsIAtom* inEventType,
|
|
|
|
nsIDOMKeyEvent* inEvent,
|
2008-04-14 21:16:24 -07:00
|
|
|
PRUint32 aCharCode, PRBool 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
|
|
|
|
//
|
|
|
|
PRBool
|
|
|
|
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)
|
2007-03-22 10:30:00 -07:00
|
|
|
return PR_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
|
|
|
nsCOMPtr<nsIDOMWindow> focusedWindow;
|
|
|
|
fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!focusedWindow)
|
|
|
|
return PR_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
|
|
|
}
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
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()) {
|
2008-09-15 18:37:13 -07:00
|
|
|
WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler, 0, PR_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;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
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,
|
|
|
|
PRBool aIgnoreShiftKey)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
nsresult rv;
|
2008-09-15 18:37:13 -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()) {
|
2008-10-09 16:23:07 -07:00
|
|
|
PRBool 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-21 22:39:53 -07:00
|
|
|
nsCOMPtr<nsIDOMDocument> domDoc(
|
|
|
|
do_QueryInterface(elt->GetCurrentDoc()));
|
|
|
|
if (domDoc)
|
|
|
|
domDoc->GetElementById(command, getter_AddRefs(commandElt));
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-14 02:11:38 -07:00
|
|
|
nsCOMPtr<nsPIDOMEventTarget> 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)) {
|
2008-04-14 21:16:24 -07:00
|
|
|
return PR_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-14 21:16:24 -07:00
|
|
|
return PR_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
|
2007-05-14 02:11:38 -07:00
|
|
|
NS_NewXBLWindowKeyHandler(nsIDOMElement* aElement, nsPIDOMEventTarget* aTarget,
|
|
|
|
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;
|
|
|
|
}
|