Back to index

lightning-sunbird  0.9+nobinonly
nsXBLWindowKeyHandler.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Original Author: David W. Hyatt (hyatt@netscape.com)
00024  *   - Mike Pinkerton (pinkerton@netscape.com)
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsCOMPtr.h"
00041 #include "nsXBLPrototypeHandler.h"
00042 #include "nsXBLWindowKeyHandler.h"
00043 #include "nsXBLAtoms.h"
00044 #include "nsIContent.h"
00045 #include "nsIAtom.h"
00046 #include "nsIDOMNSUIEvent.h"
00047 #include "nsIDOMKeyEvent.h"
00048 #include "nsIDOMEventReceiver.h"
00049 #include "nsIDOMNSEvent.h"
00050 #include "nsXBLService.h"
00051 #include "nsIServiceManager.h"
00052 #include "nsHTMLAtoms.h"
00053 #include "nsIXBLDocumentInfo.h"
00054 #include "nsIDOMElement.h"
00055 #include "nsXBLAtoms.h"
00056 #include "nsINativeKeyBindings.h"
00057 #include "nsIController.h"
00058 #include "nsIControllers.h"
00059 #include "nsIDOMWindowInternal.h"
00060 #include "nsIFocusController.h"
00061 #include "nsPIWindowRoot.h"
00062 
00063 static nsINativeKeyBindings *sNativeEditorBindings = nsnull;
00064 
00065 nsXBLWindowKeyHandler::nsXBLWindowKeyHandler(nsIDOMElement* aElement, nsIDOMEventReceiver* aReceiver)
00066   : nsXBLWindowHandler(aElement, aReceiver)
00067 {
00068 }
00069 
00070 nsXBLWindowKeyHandler::~nsXBLWindowKeyHandler()
00071 {
00072   // If mBoxObjectForElement is non-null, we created a prototype handler.
00073   if (mBoxObjectForElement)
00074     delete mHandler;
00075 }
00076 
00077 NS_IMPL_ISUPPORTS2(nsXBLWindowKeyHandler,
00078                    nsIDOMKeyListener,
00079                    nsIDOMEventListener)
00080 
00081 static void
00082 BuildHandlerChain(nsIContent* aContent, nsXBLPrototypeHandler** aResult)
00083 {
00084   nsXBLPrototypeHandler *firstHandler = nsnull, *currHandler = nsnull;
00085 
00086   PRUint32 handlerCount = aContent->GetChildCount();
00087   for (PRUint32 j = 0; j < handlerCount; j++) {
00088     nsIContent *handler = aContent->GetChildAt(j);
00089 
00090     nsXBLPrototypeHandler* newHandler = new nsXBLPrototypeHandler(handler);
00091 
00092     if (newHandler) {
00093       if (currHandler)
00094         currHandler->SetNextHandler(newHandler);
00095       else firstHandler = newHandler;
00096       currHandler = newHandler;
00097     }
00098   }
00099 
00100   *aResult = firstHandler;
00101 }
00102 
00103 //
00104 // EnsureHandlers
00105 //    
00106 // Lazily load the XBL handlers. Overridden to handle being attached
00107 // to a particular element rather than the document
00108 //
00109 nsresult
00110 nsXBLWindowKeyHandler::EnsureHandlers(PRBool *aIsEditor)
00111 {
00112   nsCOMPtr<nsIDOMElement> el = GetElement();
00113   NS_ENSURE_STATE(!mBoxObjectForElement || el);
00114   if (el) {
00115     // We are actually a XUL <keyset>.
00116     if (aIsEditor)
00117       *aIsEditor = PR_FALSE;
00118 
00119     if (mHandler)
00120       return NS_OK;
00121 
00122     nsCOMPtr<nsIContent> content(do_QueryInterface(el));
00123     BuildHandlerChain(content, &mHandler);
00124   }
00125   else // We are an XBL file of handlers.
00126     nsXBLWindowHandler::EnsureHandlers(aIsEditor);
00127   
00128   return NS_OK;
00129 }
00130 
00131 static nsINativeKeyBindings*
00132 GetEditorKeyBindings()
00133 {
00134   static PRBool noBindings = PR_FALSE;
00135   if (!sNativeEditorBindings && !noBindings) {
00136     CallGetService(NS_NATIVEKEYBINDINGS_CONTRACTID_PREFIX "editor",
00137                    &sNativeEditorBindings);
00138 
00139     if (!sNativeEditorBindings) {
00140       noBindings = PR_TRUE;
00141     }
00142   }
00143 
00144   return sNativeEditorBindings;
00145 }
00146 
00147 static void
00148 DoCommandCallback(const char *aCommand, void *aData)
00149 {
00150   nsIControllers *controllers = NS_STATIC_CAST(nsIControllers*, aData);
00151   if (controllers) {
00152     nsCOMPtr<nsIController> controller;
00153     controllers->GetControllerForCommand(aCommand, getter_AddRefs(controller));
00154     if (controller) {
00155       controller->DoCommand(aCommand);
00156     }
00157   }
00158 }
00159 
00160 NS_IMETHODIMP
00161 nsXBLWindowKeyHandler::WalkHandlers(nsIDOMEvent* aKeyEvent, nsIAtom* aEventType)
00162 {
00163   nsCOMPtr<nsIDOMNSUIEvent> evt = do_QueryInterface(aKeyEvent);
00164   PRBool prevent;
00165   evt->GetPreventDefault(&prevent);
00166   if (prevent)
00167     return NS_OK;
00168 
00169   nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aKeyEvent);
00170   PRBool trustedEvent = PR_FALSE;
00171 
00172   if (domNSEvent) {
00173     //Don't process the event if it was not dispatched from a trusted source
00174     domNSEvent->GetIsTrusted(&trustedEvent);
00175   }
00176 
00177   if (!trustedEvent)
00178     return NS_OK;
00179 
00180   // Make sure our event is really a key event
00181   nsCOMPtr<nsIDOMKeyEvent> keyEvent(do_QueryInterface(aKeyEvent));
00182   if (!keyEvent)
00183     return NS_OK;
00184 
00185   PRBool isEditor;
00186   nsresult rv = EnsureHandlers(&isEditor);
00187   NS_ENSURE_SUCCESS(rv, rv);
00188   
00189   nsCOMPtr<nsIDOMElement> el = GetElement();
00190   if (!el) {
00191     if (mUserHandler) {
00192       WalkHandlersInternal(aKeyEvent, aEventType, mUserHandler);
00193       evt->GetPreventDefault(&prevent);
00194       if (prevent)
00195         return NS_OK; // Handled by the user bindings. Our work here is done.
00196     }
00197   }
00198 
00199   WalkHandlersInternal(aKeyEvent, aEventType, mHandler);
00200 
00201   nsINativeKeyBindings *nativeBindings;
00202   if (isEditor && (nativeBindings = GetEditorKeyBindings())) {
00203     nsNativeKeyEvent nativeEvent;
00204     keyEvent->GetCharCode(&nativeEvent.charCode);
00205     keyEvent->GetKeyCode(&nativeEvent.keyCode);
00206     keyEvent->GetAltKey(&nativeEvent.altKey);
00207     keyEvent->GetCtrlKey(&nativeEvent.ctrlKey);
00208     keyEvent->GetShiftKey(&nativeEvent.shiftKey);
00209     keyEvent->GetMetaKey(&nativeEvent.metaKey);
00210 
00211     // get the DOM window we're attached to
00212     nsCOMPtr<nsIControllers> controllers;
00213     nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(mReceiver);
00214     if (root) {
00215       nsCOMPtr<nsIFocusController> fc;
00216       root->GetFocusController(getter_AddRefs(fc));
00217       if (fc) {
00218         fc->GetControllers(getter_AddRefs(controllers));
00219       }
00220     }
00221 
00222     PRBool handled;
00223     if (aEventType == nsXBLAtoms::keyup) {
00224       handled = sNativeEditorBindings->KeyUp(nativeEvent,
00225                                              DoCommandCallback, controllers);
00226     } else if (aEventType == nsXBLAtoms::keypress) {
00227       handled = sNativeEditorBindings->KeyPress(nativeEvent,
00228                                                 DoCommandCallback, controllers);
00229     } else {
00230       handled = sNativeEditorBindings->KeyDown(nativeEvent,
00231                                                DoCommandCallback, controllers);
00232     }
00233 
00234     if (handled)
00235       aKeyEvent->PreventDefault();
00236 
00237   }
00238   
00239   return NS_OK;
00240 }
00241 
00242 nsresult nsXBLWindowKeyHandler::KeyUp(nsIDOMEvent* aKeyEvent)
00243 {
00244   return WalkHandlers(aKeyEvent, nsXBLAtoms::keyup);
00245 }
00246 
00247 nsresult nsXBLWindowKeyHandler::KeyDown(nsIDOMEvent* aKeyEvent)
00248 {
00249   return WalkHandlers(aKeyEvent, nsXBLAtoms::keydown);
00250 }
00251 
00252 nsresult nsXBLWindowKeyHandler::KeyPress(nsIDOMEvent* aKeyEvent)
00253 {
00254   return WalkHandlers(aKeyEvent, nsXBLAtoms::keypress);
00255 }
00256 
00257 
00258 //
00259 // EventMatched
00260 //
00261 // See if the given handler cares about this particular key event
00262 //
00263 PRBool
00264 nsXBLWindowKeyHandler::EventMatched(nsXBLPrototypeHandler* inHandler,
00265                                     nsIAtom* inEventType, nsIDOMEvent* inEvent)
00266 {
00267   nsCOMPtr<nsIDOMKeyEvent> keyEvent(do_QueryInterface(inEvent));
00268   if (keyEvent)
00269     return inHandler->KeyEventMatched(inEventType, keyEvent);
00270 
00271   return PR_FALSE;
00272 }
00273 
00274 /* static */ void
00275 nsXBLWindowKeyHandler::ShutDown()
00276 {
00277   NS_IF_RELEASE(sNativeEditorBindings);
00278 }
00279 
00281 
00282 nsresult
00283 NS_NewXBLWindowKeyHandler(nsIDOMElement* aElement, nsIDOMEventReceiver* aReceiver, nsXBLWindowKeyHandler** aResult)
00284 {
00285   *aResult = new nsXBLWindowKeyHandler(aElement, aReceiver);
00286   if (!*aResult)
00287     return NS_ERROR_OUT_OF_MEMORY;
00288   NS_ADDREF(*aResult);
00289   return NS_OK;
00290 }