Bug 1880216 - Migrate Fenix docs into Sphinx. r=owlish,geckoview-reviewers,android...
[gecko.git] / dom / events / KeyEventHandler.cpp
blob34b7202c70f42302f41c4a25160719b8128cb005
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/ArrayUtils.h"
9 #include "ErrorList.h"
10 #include "nsCOMPtr.h"
11 #include "nsQueryObject.h"
12 #include "KeyEventHandler.h"
13 #include "nsContentUtils.h"
14 #include "nsGlobalWindowCommands.h"
15 #include "nsIContent.h"
16 #include "nsAtom.h"
17 #include "nsNameSpaceManager.h"
18 #include "mozilla/dom/Document.h"
19 #include "nsIController.h"
20 #include "nsIControllers.h"
21 #include "nsXULElement.h"
22 #include "nsFocusManager.h"
23 #include "nsIFormControl.h"
24 #include "nsPIDOMWindow.h"
25 #include "nsPIWindowRoot.h"
26 #include "nsIScriptError.h"
27 #include "nsIWeakReferenceUtils.h"
28 #include "nsString.h"
29 #include "nsReadableUtils.h"
30 #include "nsGkAtoms.h"
31 #include "nsDOMCID.h"
32 #include "nsUnicharUtils.h"
33 #include "nsCRT.h"
34 #include "nsJSUtils.h"
35 #include "mozilla/BasicEvents.h"
36 #include "mozilla/LookAndFeel.h"
37 #include "mozilla/JSEventHandler.h"
38 #include "mozilla/Preferences.h"
39 #include "mozilla/TextEvents.h"
40 #include "mozilla/dom/Element.h"
41 #include "mozilla/dom/Event.h"
42 #include "mozilla/dom/EventHandlerBinding.h"
43 #include "mozilla/dom/HTMLInputElement.h"
44 #include "mozilla/dom/HTMLTextAreaElement.h"
45 #include "mozilla/dom/KeyboardEvent.h"
46 #include "mozilla/dom/KeyboardEventBinding.h"
47 #include "mozilla/dom/ScriptSettings.h"
48 #include "mozilla/layers/KeyboardMap.h"
49 #include "xpcpublic.h"
51 namespace mozilla {
53 using namespace mozilla::layers;
55 uint32_t KeyEventHandler::gRefCnt = 0;
57 const int32_t KeyEventHandler::cShift = (1 << 0);
58 const int32_t KeyEventHandler::cAlt = (1 << 1);
59 const int32_t KeyEventHandler::cControl = (1 << 2);
60 const int32_t KeyEventHandler::cMeta = (1 << 3);
62 const int32_t KeyEventHandler::cShiftMask = (1 << 5);
63 const int32_t KeyEventHandler::cAltMask = (1 << 6);
64 const int32_t KeyEventHandler::cControlMask = (1 << 7);
65 const int32_t KeyEventHandler::cMetaMask = (1 << 8);
67 const int32_t KeyEventHandler::cAllModifiers =
68 cShiftMask | cAltMask | cControlMask | cMetaMask;
70 KeyEventHandler::KeyEventHandler(dom::Element* aHandlerElement,
71 ReservedKey aReserved)
72 : mHandlerElement(nullptr),
73 mIsXULKey(true),
74 mReserved(aReserved),
75 mNextHandler(nullptr) {
76 Init();
78 // Make sure our prototype is initialized.
79 ConstructPrototype(aHandlerElement);
82 KeyEventHandler::KeyEventHandler(ShortcutKeyData* aKeyData)
83 : mCommand(nullptr),
84 mIsXULKey(false),
85 mReserved(ReservedKey_False),
86 mNextHandler(nullptr) {
87 Init();
89 ConstructPrototype(nullptr, aKeyData->event, aKeyData->command,
90 aKeyData->keycode, aKeyData->key, aKeyData->modifiers);
93 KeyEventHandler::~KeyEventHandler() {
94 --gRefCnt;
95 if (mIsXULKey) {
96 NS_IF_RELEASE(mHandlerElement);
97 } else if (mCommand) {
98 free(mCommand);
101 // We own the next handler in the chain, so delete it now.
102 NS_CONTENT_DELETE_LIST_MEMBER(KeyEventHandler, this, mNextHandler);
105 void KeyEventHandler::GetCommand(nsAString& aCommand) const {
106 MOZ_ASSERT(aCommand.IsEmpty());
107 if (mIsXULKey) {
108 MOZ_ASSERT_UNREACHABLE("Not yet implemented");
109 return;
111 if (mCommand) {
112 aCommand.Assign(mCommand);
116 bool KeyEventHandler::TryConvertToKeyboardShortcut(
117 KeyboardShortcut* aOut) const {
118 // Convert the event type
119 KeyboardInput::KeyboardEventType eventType;
121 if (mEventName == nsGkAtoms::keydown) {
122 eventType = KeyboardInput::KEY_DOWN;
123 } else if (mEventName == nsGkAtoms::keypress) {
124 eventType = KeyboardInput::KEY_PRESS;
125 } else if (mEventName == nsGkAtoms::keyup) {
126 eventType = KeyboardInput::KEY_UP;
127 } else {
128 return false;
131 // Convert the modifiers
132 Modifiers modifiersMask = GetModifiersMask();
133 Modifiers modifiers = GetModifiers();
135 // Mask away any bits that won't be compared
136 modifiers &= modifiersMask;
138 // Convert the keyCode or charCode
139 uint32_t keyCode;
140 uint32_t charCode;
142 if (mMisc) {
143 keyCode = 0;
144 charCode = static_cast<uint32_t>(mDetail);
145 } else {
146 keyCode = static_cast<uint32_t>(mDetail);
147 charCode = 0;
150 NS_LossyConvertUTF16toASCII commandText(mCommand);
151 KeyboardScrollAction action;
152 if (!nsGlobalWindowCommands::FindScrollCommand(commandText.get(), &action)) {
153 // This action doesn't represent a scroll so we need to create a dispatch
154 // to content keyboard shortcut so APZ handles this command correctly
155 *aOut = KeyboardShortcut(eventType, keyCode, charCode, modifiers,
156 modifiersMask);
157 return true;
160 // This prototype is a command which represents a scroll action, so create
161 // a keyboard shortcut to handle it
162 *aOut = KeyboardShortcut(eventType, keyCode, charCode, modifiers,
163 modifiersMask, action);
164 return true;
167 bool KeyEventHandler::KeyElementIsDisabled() const {
168 RefPtr<dom::Element> keyElement = GetHandlerElement();
169 return keyElement &&
170 keyElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
171 nsGkAtoms::_true, eCaseMatters);
174 already_AddRefed<dom::Element> KeyEventHandler::GetHandlerElement() const {
175 if (mIsXULKey) {
176 nsCOMPtr<dom::Element> element = do_QueryReferent(mHandlerElement);
177 return element.forget();
180 return nullptr;
183 nsresult KeyEventHandler::ExecuteHandler(dom::EventTarget* aTarget,
184 dom::Event* aEvent) {
185 // In both cases the union should be defined.
186 if (!mHandlerElement) {
187 return NS_ERROR_FAILURE;
190 // XUL handlers and commands shouldn't be triggered by non-trusted
191 // events.
192 if (!aEvent->IsTrusted()) {
193 return NS_OK;
196 if (mIsXULKey) {
197 return DispatchXULKeyCommand(aEvent);
200 return DispatchXBLCommand(aTarget, aEvent);
203 nsresult KeyEventHandler::DispatchXBLCommand(dom::EventTarget* aTarget,
204 dom::Event* aEvent) {
205 // This is a special-case optimization to make command handling fast.
206 // It isn't really a part of XBL, but it helps speed things up.
208 if (aEvent) {
209 // See if preventDefault has been set. If so, don't execute.
210 if (aEvent->DefaultPrevented()) {
211 return NS_OK;
213 bool dispatchStopped = aEvent->IsDispatchStopped();
214 if (dispatchStopped) {
215 return NS_OK;
219 // Instead of executing JS, let's get the controller for the bound
220 // element and call doCommand on it.
221 nsCOMPtr<nsIController> controller;
223 nsCOMPtr<nsPIDOMWindowOuter> privateWindow;
224 nsCOMPtr<nsPIWindowRoot> windowRoot =
225 nsPIWindowRoot::FromEventTargetOrNull(aTarget);
226 if (windowRoot) {
227 privateWindow = windowRoot->GetWindow();
228 } else {
229 privateWindow = nsPIDOMWindowOuter::FromEventTargetOrNull(aTarget);
230 if (!privateWindow) {
231 nsCOMPtr<dom::Document> doc;
232 // XXXbz sXBL/XBL2 issue -- this should be the "scope doc" or
233 // something... whatever we use when wrapping DOM nodes
234 // normally. It's not clear that the owner doc is the right
235 // thing.
236 if (nsIContent* content = nsIContent::FromEventTargetOrNull(aTarget)) {
237 doc = content->OwnerDoc();
240 if (!doc) {
241 if (nsINode* node = nsINode::FromEventTargetOrNull(aTarget)) {
242 if (node->IsDocument()) {
243 doc = node->AsDocument();
248 if (!doc) {
249 return NS_ERROR_FAILURE;
252 privateWindow = doc->GetWindow();
253 if (!privateWindow) {
254 return NS_ERROR_FAILURE;
258 windowRoot = privateWindow->GetTopWindowRoot();
261 NS_LossyConvertUTF16toASCII command(mCommand);
262 if (windowRoot) {
263 // If user tries to do something, user must try to do it in visible window.
264 // So, let's retrieve controller of visible window.
265 windowRoot->GetControllerForCommand(command.get(), true,
266 getter_AddRefs(controller));
267 } else {
268 controller =
269 GetController(aTarget); // We're attached to the receiver possibly.
272 // We are the default action for this command.
273 // Stop any other default action from executing.
274 aEvent->PreventDefault();
276 if (mEventName == nsGkAtoms::keypress &&
277 mDetail == dom::KeyboardEvent_Binding::DOM_VK_SPACE && mMisc == 1) {
278 // get the focused element so that we can pageDown only at
279 // certain times.
281 nsCOMPtr<nsPIDOMWindowOuter> windowToCheck;
282 if (windowRoot) {
283 windowToCheck = windowRoot->GetWindow();
284 } else {
285 windowToCheck = privateWindow->GetPrivateRoot();
288 nsCOMPtr<nsIContent> focusedContent;
289 if (windowToCheck) {
290 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
291 focusedContent = nsFocusManager::GetFocusedDescendant(
292 windowToCheck, nsFocusManager::eIncludeAllDescendants,
293 getter_AddRefs(focusedWindow));
296 // If the focus is in an editable region, don't scroll.
297 if (focusedContent && focusedContent->IsEditable()) {
298 return NS_OK;
301 // If the focus is in a form control, don't scroll.
302 for (nsIContent* c = focusedContent; c; c = c->GetParent()) {
303 nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(c);
304 if (formControl) {
305 return NS_OK;
310 if (controller) {
311 controller->DoCommand(command.get());
314 return NS_OK;
317 nsresult KeyEventHandler::DispatchXULKeyCommand(dom::Event* aEvent) {
318 nsCOMPtr<dom::Element> handlerElement = GetHandlerElement();
319 NS_ENSURE_STATE(handlerElement);
320 if (handlerElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
321 nsGkAtoms::_true, eCaseMatters)) {
322 // Don't dispatch command events for disabled keys.
323 return NS_SUCCESS_DOM_NO_OPERATION;
326 aEvent->PreventDefault();
328 // Copy the modifiers from the key event.
329 RefPtr<dom::KeyboardEvent> domKeyboardEvent = aEvent->AsKeyboardEvent();
330 if (!domKeyboardEvent) {
331 NS_ERROR("Trying to execute a key handler for a non-key event!");
332 return NS_ERROR_FAILURE;
335 // XXX We should use mozilla::Modifiers for supporting all modifiers.
337 bool isAlt = domKeyboardEvent->AltKey();
338 bool isControl = domKeyboardEvent->CtrlKey();
339 bool isShift = domKeyboardEvent->ShiftKey();
340 bool isMeta = domKeyboardEvent->MetaKey();
342 nsContentUtils::DispatchXULCommand(handlerElement, true, nullptr, nullptr,
343 isControl, isAlt, isShift, isMeta);
344 return NS_OK;
347 Modifiers KeyEventHandler::GetModifiers() const {
348 Modifiers modifiers = 0;
350 if (mKeyMask & cMeta) {
351 modifiers |= MODIFIER_META;
353 if (mKeyMask & cShift) {
354 modifiers |= MODIFIER_SHIFT;
356 if (mKeyMask & cAlt) {
357 modifiers |= MODIFIER_ALT;
359 if (mKeyMask & cControl) {
360 modifiers |= MODIFIER_CONTROL;
363 return modifiers;
366 Modifiers KeyEventHandler::GetModifiersMask() const {
367 Modifiers modifiersMask = 0;
369 if (mKeyMask & cMetaMask) {
370 modifiersMask |= MODIFIER_META;
372 if (mKeyMask & cShiftMask) {
373 modifiersMask |= MODIFIER_SHIFT;
375 if (mKeyMask & cAltMask) {
376 modifiersMask |= MODIFIER_ALT;
378 if (mKeyMask & cControlMask) {
379 modifiersMask |= MODIFIER_CONTROL;
382 return modifiersMask;
385 already_AddRefed<nsIController> KeyEventHandler::GetController(
386 dom::EventTarget* aTarget) {
387 if (!aTarget) {
388 return nullptr;
391 // XXX Fix this so there's a generic interface that describes controllers,
392 // This code should have no special knowledge of what objects might have
393 // controllers.
394 nsCOMPtr<nsIControllers> controllers;
396 if (nsIContent* targetContent = nsIContent::FromEventTarget(aTarget)) {
397 RefPtr<nsXULElement> xulElement = nsXULElement::FromNode(targetContent);
398 if (xulElement) {
399 controllers = xulElement->GetControllers(IgnoreErrors());
402 if (!controllers) {
403 dom::HTMLTextAreaElement* htmlTextArea =
404 dom::HTMLTextAreaElement::FromNode(targetContent);
405 if (htmlTextArea) {
406 htmlTextArea->GetControllers(getter_AddRefs(controllers));
410 if (!controllers) {
411 dom::HTMLInputElement* htmlInputElement =
412 dom::HTMLInputElement::FromNode(targetContent);
413 if (htmlInputElement) {
414 htmlInputElement->GetControllers(getter_AddRefs(controllers));
419 if (!controllers) {
420 if (nsCOMPtr<nsPIDOMWindowOuter> domWindow =
421 nsPIDOMWindowOuter::FromEventTarget(aTarget)) {
422 domWindow->GetControllers(getter_AddRefs(controllers));
426 // Return the first controller.
427 // XXX This code should be checking the command name and using supportscommand
428 // and iscommandenabled.
429 nsCOMPtr<nsIController> controller;
430 if (controllers) {
431 controllers->GetControllerAt(0, getter_AddRefs(controller));
434 return controller.forget();
437 bool KeyEventHandler::KeyEventMatched(
438 dom::KeyboardEvent* aDomKeyboardEvent, uint32_t aCharCode,
439 const IgnoreModifierState& aIgnoreModifierState) {
440 if (mDetail != -1) {
441 // Get the keycode or charcode of the key event.
442 uint32_t code;
444 if (mMisc) {
445 if (aCharCode) {
446 code = aCharCode;
447 } else {
448 code = aDomKeyboardEvent->CharCode();
450 if (IS_IN_BMP(code)) {
451 code = ToLowerCase(char16_t(code));
453 } else {
454 code = aDomKeyboardEvent->KeyCode();
457 if (code != static_cast<uint32_t>(mDetail)) {
458 return false;
462 return ModifiersMatchMask(aDomKeyboardEvent, aIgnoreModifierState);
465 struct keyCodeData {
466 const char* str;
467 uint16_t strlength;
468 uint16_t keycode;
471 // All of these must be uppercase, since the function below does
472 // case-insensitive comparison by converting to uppercase.
473 // XXX: be sure to check this periodically for new symbol additions!
474 static const keyCodeData gKeyCodes[] = {
476 #define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) \
477 {#aDOMKeyName, sizeof(#aDOMKeyName) - 1, aDOMKeyCode},
478 #include "mozilla/VirtualKeyCodeList.h"
479 #undef NS_DEFINE_VK
481 {nullptr, 0, 0}};
483 int32_t KeyEventHandler::GetMatchingKeyCode(const nsAString& aKeyName) {
484 nsAutoCString keyName;
485 LossyCopyUTF16toASCII(aKeyName, keyName);
486 ToUpperCase(keyName); // We want case-insensitive comparison with data
487 // stored as uppercase.
489 uint32_t keyNameLength = keyName.Length();
490 const char* keyNameStr = keyName.get();
491 for (unsigned long i = 0; i < ArrayLength(gKeyCodes) - 1; ++i) {
492 if (keyNameLength == gKeyCodes[i].strlength &&
493 !nsCRT::strcmp(gKeyCodes[i].str, keyNameStr)) {
494 return gKeyCodes[i].keycode;
498 return 0;
501 int32_t KeyEventHandler::KeyToMask(uint32_t key) {
502 switch (key) {
503 case dom::KeyboardEvent_Binding::DOM_VK_META:
504 case dom::KeyboardEvent_Binding::DOM_VK_WIN:
505 return cMeta | cMetaMask;
507 case dom::KeyboardEvent_Binding::DOM_VK_ALT:
508 return cAlt | cAltMask;
510 case dom::KeyboardEvent_Binding::DOM_VK_CONTROL:
511 default:
512 return cControl | cControlMask;
516 // static
517 int32_t KeyEventHandler::AccelKeyMask() {
518 switch (WidgetInputEvent::AccelModifier()) {
519 case MODIFIER_ALT:
520 return KeyToMask(dom::KeyboardEvent_Binding::DOM_VK_ALT);
521 case MODIFIER_CONTROL:
522 return KeyToMask(dom::KeyboardEvent_Binding::DOM_VK_CONTROL);
523 case MODIFIER_META:
524 return KeyToMask(dom::KeyboardEvent_Binding::DOM_VK_META);
525 default:
526 MOZ_CRASH("Handle the new result of WidgetInputEvent::AccelModifier()");
527 return 0;
531 void KeyEventHandler::GetEventType(nsAString& aEvent) {
532 nsCOMPtr<dom::Element> handlerElement = GetHandlerElement();
533 if (!handlerElement) {
534 aEvent.Truncate();
535 return;
537 handlerElement->GetAttr(nsGkAtoms::event, aEvent);
539 if (aEvent.IsEmpty() && mIsXULKey) {
540 // If no type is specified for a XUL <key> element, let's assume that we're
541 // "keypress".
542 aEvent.AssignLiteral("keypress");
546 void KeyEventHandler::ConstructPrototype(dom::Element* aKeyElement,
547 const char16_t* aEvent,
548 const char16_t* aCommand,
549 const char16_t* aKeyCode,
550 const char16_t* aCharCode,
551 const char16_t* aModifiers) {
552 mDetail = -1;
553 mMisc = 0;
554 mKeyMask = 0;
555 nsAutoString modifiers;
557 if (mIsXULKey) {
558 nsWeakPtr weak = do_GetWeakReference(aKeyElement);
559 if (!weak) {
560 return;
562 weak.swap(mHandlerElement);
564 nsAutoString event;
565 GetEventType(event);
566 if (event.IsEmpty()) {
567 return;
569 mEventName = NS_Atomize(event);
571 aKeyElement->GetAttr(nsGkAtoms::modifiers, modifiers);
572 } else {
573 mCommand = ToNewUnicode(nsDependentString(aCommand));
574 mEventName = NS_Atomize(aEvent);
575 modifiers = aModifiers;
578 BuildModifiers(modifiers);
580 nsAutoString key(aCharCode);
581 if (key.IsEmpty()) {
582 if (mIsXULKey) {
583 aKeyElement->GetAttr(nsGkAtoms::key, key);
584 if (key.IsEmpty()) {
585 aKeyElement->GetAttr(nsGkAtoms::charcode, key);
590 if (!key.IsEmpty()) {
591 if (mKeyMask == 0) {
592 mKeyMask = cAllModifiers;
594 ToLowerCase(key);
596 // We have a charcode.
597 mMisc = 1;
598 mDetail = key[0];
599 const uint8_t GTK2Modifiers = cShift | cControl | cShiftMask | cControlMask;
600 if (mIsXULKey && (mKeyMask & GTK2Modifiers) == GTK2Modifiers &&
601 modifiers.First() != char16_t(',') &&
602 (mDetail == 'u' || mDetail == 'U')) {
603 ReportKeyConflict(key.get(), modifiers.get(), aKeyElement,
604 "GTK2Conflict2");
606 const uint8_t WinModifiers = cControl | cAlt | cControlMask | cAltMask;
607 if (mIsXULKey && (mKeyMask & WinModifiers) == WinModifiers &&
608 modifiers.First() != char16_t(',') &&
609 (('A' <= mDetail && mDetail <= 'Z') ||
610 ('a' <= mDetail && mDetail <= 'z'))) {
611 ReportKeyConflict(key.get(), modifiers.get(), aKeyElement,
612 "WinConflict2");
614 } else {
615 key.Assign(aKeyCode);
616 if (mIsXULKey) {
617 aKeyElement->GetAttr(nsGkAtoms::keycode, key);
620 if (!key.IsEmpty()) {
621 if (mKeyMask == 0) {
622 mKeyMask = cAllModifiers;
624 mDetail = GetMatchingKeyCode(key);
629 void KeyEventHandler::BuildModifiers(nsAString& aModifiers) {
630 if (!aModifiers.IsEmpty()) {
631 mKeyMask = cAllModifiers;
632 char* str = ToNewCString(aModifiers);
633 char* newStr;
634 char* token = nsCRT::strtok(str, ", \t", &newStr);
635 while (token != nullptr) {
636 if (strcmp(token, "shift") == 0) {
637 mKeyMask |= cShift | cShiftMask;
638 } else if (strcmp(token, "alt") == 0) {
639 mKeyMask |= cAlt | cAltMask;
640 } else if (strcmp(token, "meta") == 0) {
641 mKeyMask |= cMeta | cMetaMask;
642 } else if (strcmp(token, "control") == 0) {
643 mKeyMask |= cControl | cControlMask;
644 } else if (strcmp(token, "accel") == 0) {
645 mKeyMask |= AccelKeyMask();
646 } else if (strcmp(token, "access") == 0) {
647 mKeyMask |= KeyToMask(LookAndFeel::GetMenuAccessKey());
648 } else if (strcmp(token, "any") == 0) {
649 mKeyMask &= ~(mKeyMask << 5);
652 token = nsCRT::strtok(newStr, ", \t", &newStr);
655 free(str);
659 void KeyEventHandler::ReportKeyConflict(const char16_t* aKey,
660 const char16_t* aModifiers,
661 dom::Element* aKeyElement,
662 const char* aMessageName) {
663 nsCOMPtr<dom::Document> doc = aKeyElement->OwnerDoc();
665 nsAutoString id;
666 aKeyElement->GetAttr(nsGkAtoms::id, id);
667 AutoTArray<nsString, 3> params;
668 params.AppendElement(aKey);
669 params.AppendElement(aModifiers);
670 params.AppendElement(id);
671 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
672 "Key dom::Event Handler"_ns, doc,
673 nsContentUtils::eDOM_PROPERTIES, aMessageName,
674 params, nullptr, u""_ns, 0);
677 bool KeyEventHandler::ModifiersMatchMask(
678 dom::UIEvent* aEvent, const IgnoreModifierState& aIgnoreModifierState) {
679 WidgetInputEvent* inputEvent = aEvent->WidgetEventPtr()->AsInputEvent();
680 NS_ENSURE_TRUE(inputEvent, false);
682 if ((mKeyMask & cMetaMask) && !aIgnoreModifierState.mMeta) {
683 if (inputEvent->IsMeta() != ((mKeyMask & cMeta) != 0)) {
684 return false;
688 if ((mKeyMask & cShiftMask) && !aIgnoreModifierState.mShift) {
689 if (inputEvent->IsShift() != ((mKeyMask & cShift) != 0)) {
690 return false;
694 if (mKeyMask & cAltMask) {
695 if (inputEvent->IsAlt() != ((mKeyMask & cAlt) != 0)) {
696 return false;
700 if (mKeyMask & cControlMask) {
701 if (inputEvent->IsControl() != ((mKeyMask & cControl) != 0)) {
702 return false;
706 return true;
709 size_t KeyEventHandler::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
710 size_t n = 0;
711 for (const KeyEventHandler* handler = this; handler;
712 handler = handler->mNextHandler) {
713 n += aMallocSizeOf(handler);
714 if (!mIsXULKey) {
715 n += aMallocSizeOf(handler->mCommand);
718 return n;
721 } // namespace mozilla