Backed out changeset 0c01a856e4c3 (bug 1870427) as requested by Emilio CLOSED TREE
[gecko.git] / dom / events / KeyEventHandler.cpp
blob662de2af95fbb8fd9fd70fc814fc0539d8e93cf5
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 if (nsIFormControl::FromNode(c)) {
304 return NS_OK;
309 if (controller) {
310 controller->DoCommand(command.get());
313 return NS_OK;
316 nsresult KeyEventHandler::DispatchXULKeyCommand(dom::Event* aEvent) {
317 nsCOMPtr<dom::Element> handlerElement = GetHandlerElement();
318 NS_ENSURE_STATE(handlerElement);
319 if (handlerElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
320 nsGkAtoms::_true, eCaseMatters)) {
321 // Don't dispatch command events for disabled keys.
322 return NS_SUCCESS_DOM_NO_OPERATION;
325 aEvent->PreventDefault();
327 // Copy the modifiers from the key event.
328 RefPtr<dom::KeyboardEvent> domKeyboardEvent = aEvent->AsKeyboardEvent();
329 if (!domKeyboardEvent) {
330 NS_ERROR("Trying to execute a key handler for a non-key event!");
331 return NS_ERROR_FAILURE;
334 // XXX We should use mozilla::Modifiers for supporting all modifiers.
336 bool isAlt = domKeyboardEvent->AltKey();
337 bool isControl = domKeyboardEvent->CtrlKey();
338 bool isShift = domKeyboardEvent->ShiftKey();
339 bool isMeta = domKeyboardEvent->MetaKey();
341 nsContentUtils::DispatchXULCommand(handlerElement, true, nullptr, nullptr,
342 isControl, isAlt, isShift, isMeta);
343 return NS_OK;
346 Modifiers KeyEventHandler::GetModifiers() const {
347 Modifiers modifiers = 0;
349 if (mKeyMask & cMeta) {
350 modifiers |= MODIFIER_META;
352 if (mKeyMask & cShift) {
353 modifiers |= MODIFIER_SHIFT;
355 if (mKeyMask & cAlt) {
356 modifiers |= MODIFIER_ALT;
358 if (mKeyMask & cControl) {
359 modifiers |= MODIFIER_CONTROL;
362 return modifiers;
365 Modifiers KeyEventHandler::GetModifiersMask() const {
366 Modifiers modifiersMask = 0;
368 if (mKeyMask & cMetaMask) {
369 modifiersMask |= MODIFIER_META;
371 if (mKeyMask & cShiftMask) {
372 modifiersMask |= MODIFIER_SHIFT;
374 if (mKeyMask & cAltMask) {
375 modifiersMask |= MODIFIER_ALT;
377 if (mKeyMask & cControlMask) {
378 modifiersMask |= MODIFIER_CONTROL;
381 return modifiersMask;
384 already_AddRefed<nsIController> KeyEventHandler::GetController(
385 dom::EventTarget* aTarget) {
386 if (!aTarget) {
387 return nullptr;
390 // XXX Fix this so there's a generic interface that describes controllers,
391 // This code should have no special knowledge of what objects might have
392 // controllers.
393 nsCOMPtr<nsIControllers> controllers;
395 if (nsIContent* targetContent = nsIContent::FromEventTarget(aTarget)) {
396 RefPtr<nsXULElement> xulElement = nsXULElement::FromNode(targetContent);
397 if (xulElement) {
398 controllers = xulElement->GetControllers(IgnoreErrors());
401 if (!controllers) {
402 dom::HTMLTextAreaElement* htmlTextArea =
403 dom::HTMLTextAreaElement::FromNode(targetContent);
404 if (htmlTextArea) {
405 htmlTextArea->GetControllers(getter_AddRefs(controllers));
409 if (!controllers) {
410 dom::HTMLInputElement* htmlInputElement =
411 dom::HTMLInputElement::FromNode(targetContent);
412 if (htmlInputElement) {
413 htmlInputElement->GetControllers(getter_AddRefs(controllers));
418 if (!controllers) {
419 if (nsCOMPtr<nsPIDOMWindowOuter> domWindow =
420 nsPIDOMWindowOuter::FromEventTarget(aTarget)) {
421 domWindow->GetControllers(getter_AddRefs(controllers));
425 // Return the first controller.
426 // XXX This code should be checking the command name and using supportscommand
427 // and iscommandenabled.
428 nsCOMPtr<nsIController> controller;
429 if (controllers) {
430 controllers->GetControllerAt(0, getter_AddRefs(controller));
433 return controller.forget();
436 bool KeyEventHandler::KeyEventMatched(
437 dom::KeyboardEvent* aDomKeyboardEvent, uint32_t aCharCode,
438 const IgnoreModifierState& aIgnoreModifierState) {
439 if (mDetail != -1) {
440 // Get the keycode or charcode of the key event.
441 uint32_t code;
443 if (mMisc) {
444 if (aCharCode) {
445 code = aCharCode;
446 } else {
447 code = aDomKeyboardEvent->CharCode();
449 if (IS_IN_BMP(code)) {
450 code = ToLowerCase(char16_t(code));
452 } else {
453 code = aDomKeyboardEvent->KeyCode();
456 if (code != static_cast<uint32_t>(mDetail)) {
457 return false;
461 return ModifiersMatchMask(aDomKeyboardEvent, aIgnoreModifierState);
464 struct keyCodeData {
465 const char* str;
466 uint16_t strlength;
467 uint16_t keycode;
470 // All of these must be uppercase, since the function below does
471 // case-insensitive comparison by converting to uppercase.
472 // XXX: be sure to check this periodically for new symbol additions!
473 static const keyCodeData gKeyCodes[] = {
475 #define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) \
476 {#aDOMKeyName, sizeof(#aDOMKeyName) - 1, aDOMKeyCode},
477 #include "mozilla/VirtualKeyCodeList.h"
478 #undef NS_DEFINE_VK
480 {nullptr, 0, 0}};
482 int32_t KeyEventHandler::GetMatchingKeyCode(const nsAString& aKeyName) {
483 nsAutoCString keyName;
484 LossyCopyUTF16toASCII(aKeyName, keyName);
485 ToUpperCase(keyName); // We want case-insensitive comparison with data
486 // stored as uppercase.
488 uint32_t keyNameLength = keyName.Length();
489 const char* keyNameStr = keyName.get();
490 for (unsigned long i = 0; i < std::size(gKeyCodes) - 1; ++i) {
491 if (keyNameLength == gKeyCodes[i].strlength &&
492 !nsCRT::strcmp(gKeyCodes[i].str, keyNameStr)) {
493 return gKeyCodes[i].keycode;
497 return 0;
500 int32_t KeyEventHandler::KeyToMask(uint32_t key) {
501 switch (key) {
502 case dom::KeyboardEvent_Binding::DOM_VK_META:
503 case dom::KeyboardEvent_Binding::DOM_VK_WIN:
504 return cMeta | cMetaMask;
506 case dom::KeyboardEvent_Binding::DOM_VK_ALT:
507 return cAlt | cAltMask;
509 case dom::KeyboardEvent_Binding::DOM_VK_CONTROL:
510 default:
511 return cControl | cControlMask;
515 // static
516 int32_t KeyEventHandler::AccelKeyMask() {
517 switch (WidgetInputEvent::AccelModifier()) {
518 case MODIFIER_ALT:
519 return KeyToMask(dom::KeyboardEvent_Binding::DOM_VK_ALT);
520 case MODIFIER_CONTROL:
521 return KeyToMask(dom::KeyboardEvent_Binding::DOM_VK_CONTROL);
522 case MODIFIER_META:
523 return KeyToMask(dom::KeyboardEvent_Binding::DOM_VK_META);
524 default:
525 MOZ_CRASH("Handle the new result of WidgetInputEvent::AccelModifier()");
526 return 0;
530 void KeyEventHandler::GetEventType(nsAString& aEvent) {
531 nsCOMPtr<dom::Element> handlerElement = GetHandlerElement();
532 if (!handlerElement) {
533 aEvent.Truncate();
534 return;
536 handlerElement->GetAttr(nsGkAtoms::event, aEvent);
538 if (aEvent.IsEmpty() && mIsXULKey) {
539 // If no type is specified for a XUL <key> element, let's assume that we're
540 // "keypress".
541 aEvent.AssignLiteral("keypress");
545 void KeyEventHandler::ConstructPrototype(dom::Element* aKeyElement,
546 const char16_t* aEvent,
547 const char16_t* aCommand,
548 const char16_t* aKeyCode,
549 const char16_t* aCharCode,
550 const char16_t* aModifiers) {
551 mDetail = -1;
552 mMisc = 0;
553 mKeyMask = 0;
554 nsAutoString modifiers;
556 if (mIsXULKey) {
557 nsWeakPtr weak = do_GetWeakReference(aKeyElement);
558 if (!weak) {
559 return;
561 weak.swap(mHandlerElement);
563 nsAutoString event;
564 GetEventType(event);
565 if (event.IsEmpty()) {
566 return;
568 mEventName = NS_Atomize(event);
570 aKeyElement->GetAttr(nsGkAtoms::modifiers, modifiers);
571 } else {
572 mCommand = ToNewUnicode(nsDependentString(aCommand));
573 mEventName = NS_Atomize(aEvent);
574 modifiers = aModifiers;
577 BuildModifiers(modifiers);
579 nsAutoString key(aCharCode);
580 if (key.IsEmpty()) {
581 if (mIsXULKey) {
582 aKeyElement->GetAttr(nsGkAtoms::key, key);
583 if (key.IsEmpty()) {
584 aKeyElement->GetAttr(nsGkAtoms::charcode, key);
589 if (!key.IsEmpty()) {
590 if (mKeyMask == 0) {
591 mKeyMask = cAllModifiers;
593 ToLowerCase(key);
595 // We have a charcode.
596 mMisc = 1;
597 mDetail = key[0];
598 const uint8_t GTK2Modifiers = cShift | cControl | cShiftMask | cControlMask;
599 if (mIsXULKey && (mKeyMask & GTK2Modifiers) == GTK2Modifiers &&
600 modifiers.First() != char16_t(',') &&
601 (mDetail == 'u' || mDetail == 'U')) {
602 ReportKeyConflict(key.get(), modifiers.get(), aKeyElement,
603 "GTK2Conflict2");
605 const uint8_t WinModifiers = cControl | cAlt | cControlMask | cAltMask;
606 if (mIsXULKey && (mKeyMask & WinModifiers) == WinModifiers &&
607 modifiers.First() != char16_t(',') &&
608 (('A' <= mDetail && mDetail <= 'Z') ||
609 ('a' <= mDetail && mDetail <= 'z'))) {
610 ReportKeyConflict(key.get(), modifiers.get(), aKeyElement,
611 "WinConflict2");
613 } else {
614 key.Assign(aKeyCode);
615 if (mIsXULKey) {
616 aKeyElement->GetAttr(nsGkAtoms::keycode, key);
619 if (!key.IsEmpty()) {
620 if (mKeyMask == 0) {
621 mKeyMask = cAllModifiers;
623 mDetail = GetMatchingKeyCode(key);
628 void KeyEventHandler::BuildModifiers(nsAString& aModifiers) {
629 if (!aModifiers.IsEmpty()) {
630 mKeyMask = cAllModifiers;
631 char* str = ToNewCString(aModifiers);
632 char* newStr;
633 char* token = nsCRT::strtok(str, ", \t", &newStr);
634 while (token != nullptr) {
635 if (strcmp(token, "shift") == 0) {
636 mKeyMask |= cShift | cShiftMask;
637 } else if (strcmp(token, "alt") == 0) {
638 mKeyMask |= cAlt | cAltMask;
639 } else if (strcmp(token, "meta") == 0) {
640 mKeyMask |= cMeta | cMetaMask;
641 } else if (strcmp(token, "control") == 0) {
642 mKeyMask |= cControl | cControlMask;
643 } else if (strcmp(token, "accel") == 0) {
644 mKeyMask |= AccelKeyMask();
645 } else if (strcmp(token, "access") == 0) {
646 mKeyMask |= KeyToMask(LookAndFeel::GetMenuAccessKey());
647 } else if (strcmp(token, "any") == 0) {
648 mKeyMask &= ~(mKeyMask << 5);
651 token = nsCRT::strtok(newStr, ", \t", &newStr);
654 free(str);
658 void KeyEventHandler::ReportKeyConflict(const char16_t* aKey,
659 const char16_t* aModifiers,
660 dom::Element* aKeyElement,
661 const char* aMessageName) {
662 nsCOMPtr<dom::Document> doc = aKeyElement->OwnerDoc();
664 nsAutoString id;
665 aKeyElement->GetAttr(nsGkAtoms::id, id);
666 AutoTArray<nsString, 3> params;
667 params.AppendElement(aKey);
668 params.AppendElement(aModifiers);
669 params.AppendElement(id);
670 nsContentUtils::ReportToConsole(
671 nsIScriptError::warningFlag, "Key dom::Event Handler"_ns, doc,
672 nsContentUtils::eDOM_PROPERTIES, aMessageName, params);
675 bool KeyEventHandler::ModifiersMatchMask(
676 dom::UIEvent* aEvent, const IgnoreModifierState& aIgnoreModifierState) {
677 WidgetInputEvent* inputEvent = aEvent->WidgetEventPtr()->AsInputEvent();
678 NS_ENSURE_TRUE(inputEvent, false);
680 if ((mKeyMask & cMetaMask) && !aIgnoreModifierState.mMeta) {
681 if (inputEvent->IsMeta() != ((mKeyMask & cMeta) != 0)) {
682 return false;
686 if ((mKeyMask & cShiftMask) && !aIgnoreModifierState.mShift) {
687 if (inputEvent->IsShift() != ((mKeyMask & cShift) != 0)) {
688 return false;
692 if (mKeyMask & cAltMask) {
693 if (inputEvent->IsAlt() != ((mKeyMask & cAlt) != 0)) {
694 return false;
698 if (mKeyMask & cControlMask) {
699 if (inputEvent->IsControl() != ((mKeyMask & cControl) != 0)) {
700 return false;
704 return true;
707 size_t KeyEventHandler::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
708 size_t n = 0;
709 for (const KeyEventHandler* handler = this; handler;
710 handler = handler->mNextHandler) {
711 n += aMallocSizeOf(handler);
712 if (!mIsXULKey) {
713 n += aMallocSizeOf(handler->mCommand);
716 return n;
719 } // namespace mozilla