KeyEventHandler.cpp (21028B)
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/. */ 6 7 #include "KeyEventHandler.h" 8 9 #include "ErrorList.h" 10 #include "mozilla/BasicEvents.h" 11 #include "mozilla/JSEventHandler.h" 12 #include "mozilla/LookAndFeel.h" 13 #include "mozilla/Preferences.h" 14 #include "mozilla/TextEvents.h" 15 #include "mozilla/dom/Document.h" 16 #include "mozilla/dom/Element.h" 17 #include "mozilla/dom/Event.h" 18 #include "mozilla/dom/EventHandlerBinding.h" 19 #include "mozilla/dom/HTMLInputElement.h" 20 #include "mozilla/dom/HTMLTextAreaElement.h" 21 #include "mozilla/dom/KeyboardEvent.h" 22 #include "mozilla/dom/KeyboardEventBinding.h" 23 #include "mozilla/dom/ScriptSettings.h" 24 #include "mozilla/layers/KeyboardMap.h" 25 #include "nsAtom.h" 26 #include "nsCOMPtr.h" 27 #include "nsCRT.h" 28 #include "nsContentUtils.h" 29 #include "nsDOMCID.h" 30 #include "nsFocusManager.h" 31 #include "nsGkAtoms.h" 32 #include "nsGlobalWindowCommands.h" 33 #include "nsIContent.h" 34 #include "nsIController.h" 35 #include "nsIControllers.h" 36 #include "nsIFormControl.h" 37 #include "nsIScriptError.h" 38 #include "nsIWeakReferenceUtils.h" 39 #include "nsJSUtils.h" 40 #include "nsNameSpaceManager.h" 41 #include "nsPIDOMWindow.h" 42 #include "nsPIWindowRoot.h" 43 #include "nsQueryObject.h" 44 #include "nsReadableUtils.h" 45 #include "nsString.h" 46 #include "nsUnicharUtils.h" 47 #include "nsXULElement.h" 48 #include "xpcpublic.h" 49 50 namespace mozilla { 51 52 using namespace mozilla::layers; 53 54 uint32_t KeyEventHandler::gRefCnt = 0; 55 56 const int32_t KeyEventHandler::cShift = (1 << 0); 57 const int32_t KeyEventHandler::cAlt = (1 << 1); 58 const int32_t KeyEventHandler::cControl = (1 << 2); 59 const int32_t KeyEventHandler::cMeta = (1 << 3); 60 61 const int32_t KeyEventHandler::cShiftMask = (1 << 5); 62 const int32_t KeyEventHandler::cAltMask = (1 << 6); 63 const int32_t KeyEventHandler::cControlMask = (1 << 7); 64 const int32_t KeyEventHandler::cMetaMask = (1 << 8); 65 66 const int32_t KeyEventHandler::cAllModifiers = 67 cShiftMask | cAltMask | cControlMask | cMetaMask; 68 69 KeyEventHandler::KeyEventHandler(dom::Element* aHandlerElement, 70 ReservedKey aReserved) 71 : mHandlerElement(nullptr), 72 mIsXULKey(true), 73 mReserved(aReserved), 74 mNextHandler(nullptr) { 75 Init(); 76 77 // Make sure our prototype is initialized. 78 ConstructPrototype(aHandlerElement); 79 } 80 81 KeyEventHandler::KeyEventHandler(ShortcutKeyData* aKeyData) 82 : mCommand(nullptr), 83 mIsXULKey(false), 84 mReserved(ReservedKey_False), 85 mNextHandler(nullptr) { 86 Init(); 87 88 ConstructPrototype(nullptr, aKeyData->event, aKeyData->command, 89 aKeyData->keycode, aKeyData->key, aKeyData->modifiers); 90 } 91 92 KeyEventHandler::~KeyEventHandler() { 93 --gRefCnt; 94 if (mIsXULKey) { 95 NS_IF_RELEASE(mHandlerElement); 96 } else if (mCommand) { 97 free(mCommand); 98 } 99 100 // We own the next handler in the chain, so delete it now. 101 NS_CONTENT_DELETE_LIST_MEMBER(KeyEventHandler, this, mNextHandler); 102 } 103 104 void KeyEventHandler::GetCommand(nsAString& aCommand) const { 105 MOZ_ASSERT(aCommand.IsEmpty()); 106 if (mIsXULKey) { 107 MOZ_ASSERT_UNREACHABLE("Not yet implemented"); 108 return; 109 } 110 if (mCommand) { 111 aCommand.Assign(mCommand); 112 } 113 } 114 115 bool KeyEventHandler::TryConvertToKeyboardShortcut( 116 KeyboardShortcut* aOut) const { 117 // Convert the event type 118 KeyboardInput::KeyboardEventType eventType; 119 120 if (mEventName == nsGkAtoms::keydown) { 121 eventType = KeyboardInput::KEY_DOWN; 122 } else if (mEventName == nsGkAtoms::keypress) { 123 eventType = KeyboardInput::KEY_PRESS; 124 } else if (mEventName == nsGkAtoms::keyup) { 125 eventType = KeyboardInput::KEY_UP; 126 } else { 127 return false; 128 } 129 130 // Convert the modifiers 131 Modifiers modifiersMask = GetModifiersMask(); 132 Modifiers modifiers = GetModifiers(); 133 134 // Mask away any bits that won't be compared 135 modifiers &= modifiersMask; 136 137 // Convert the keyCode or charCode 138 uint32_t keyCode; 139 uint32_t charCode; 140 141 if (mMisc) { 142 keyCode = 0; 143 charCode = static_cast<uint32_t>(mDetail); 144 } else { 145 keyCode = static_cast<uint32_t>(mDetail); 146 charCode = 0; 147 } 148 149 NS_LossyConvertUTF16toASCII commandText(mCommand); 150 KeyboardScrollAction action; 151 if (!nsGlobalWindowCommands::FindScrollCommand(commandText, &action)) { 152 // This action doesn't represent a scroll so we need to create a dispatch 153 // to content keyboard shortcut so APZ handles this command correctly 154 *aOut = KeyboardShortcut(eventType, keyCode, charCode, modifiers, 155 modifiersMask); 156 return true; 157 } 158 159 // This prototype is a command which represents a scroll action, so create 160 // a keyboard shortcut to handle it 161 *aOut = KeyboardShortcut(eventType, keyCode, charCode, modifiers, 162 modifiersMask, action); 163 return true; 164 } 165 166 bool KeyEventHandler::KeyElementIsDisabled() const { 167 RefPtr<dom::Element> keyElement = GetHandlerElement(); 168 return keyElement && 169 keyElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled, 170 nsGkAtoms::_true, eCaseMatters); 171 } 172 173 already_AddRefed<dom::Element> KeyEventHandler::GetHandlerElement() const { 174 if (mIsXULKey) { 175 nsCOMPtr<dom::Element> element = do_QueryReferent(mHandlerElement); 176 return element.forget(); 177 } 178 179 return nullptr; 180 } 181 182 nsresult KeyEventHandler::ExecuteHandler(dom::EventTarget* aTarget, 183 dom::Event* aEvent) { 184 // In both cases the union should be defined. 185 if (!mHandlerElement) { 186 return NS_ERROR_FAILURE; 187 } 188 189 // XUL handlers and commands shouldn't be triggered by non-trusted 190 // events. 191 if (!aEvent->IsTrusted()) { 192 return NS_OK; 193 } 194 195 if (mIsXULKey) { 196 return DispatchXULKeyCommand(aEvent); 197 } 198 199 return DispatchXBLCommand(aTarget, aEvent); 200 } 201 202 nsresult KeyEventHandler::DispatchXBLCommand(dom::EventTarget* aTarget, 203 dom::Event* aEvent) { 204 // This is a special-case optimization to make command handling fast. 205 // It isn't really a part of XBL, but it helps speed things up. 206 207 if (aEvent) { 208 // See if preventDefault has been set. If so, don't execute. 209 if (aEvent->DefaultPrevented()) { 210 return NS_OK; 211 } 212 bool dispatchStopped = aEvent->IsDispatchStopped(); 213 if (dispatchStopped) { 214 return NS_OK; 215 } 216 } 217 218 // Instead of executing JS, let's get the controller for the bound 219 // element and call doCommand on it. 220 nsCOMPtr<nsIController> controller; 221 222 nsCOMPtr<nsPIDOMWindowOuter> privateWindow; 223 nsCOMPtr<nsPIWindowRoot> windowRoot = 224 nsPIWindowRoot::FromEventTargetOrNull(aTarget); 225 if (windowRoot) { 226 privateWindow = windowRoot->GetWindow(); 227 } else { 228 privateWindow = nsPIDOMWindowOuter::FromEventTargetOrNull(aTarget); 229 if (!privateWindow) { 230 nsCOMPtr<dom::Document> doc; 231 // XXXbz sXBL/XBL2 issue -- this should be the "scope doc" or 232 // something... whatever we use when wrapping DOM nodes 233 // normally. It's not clear that the owner doc is the right 234 // thing. 235 if (nsIContent* content = nsIContent::FromEventTargetOrNull(aTarget)) { 236 doc = content->OwnerDoc(); 237 } 238 239 if (!doc) { 240 if (nsINode* node = nsINode::FromEventTargetOrNull(aTarget)) { 241 if (node->IsDocument()) { 242 doc = node->AsDocument(); 243 } 244 } 245 } 246 247 if (!doc) { 248 return NS_ERROR_FAILURE; 249 } 250 251 privateWindow = doc->GetWindow(); 252 if (!privateWindow) { 253 return NS_ERROR_FAILURE; 254 } 255 } 256 257 windowRoot = privateWindow->GetTopWindowRoot(); 258 } 259 260 NS_LossyConvertUTF16toASCII command(mCommand); 261 if (windowRoot) { 262 // If user tries to do something, user must try to do it in visible window. 263 // So, let's retrieve controller of visible window. 264 windowRoot->GetControllerForCommand(command.get(), true, 265 getter_AddRefs(controller)); 266 } else { 267 controller = 268 GetController(aTarget); // We're attached to the receiver possibly. 269 } 270 271 // We are the default action for this command. 272 // Stop any other default action from executing. 273 aEvent->PreventDefault(); 274 275 if (mEventName == nsGkAtoms::keypress && 276 mDetail == dom::KeyboardEvent_Binding::DOM_VK_SPACE && mMisc == 1) { 277 // get the focused element so that we can pageDown only at 278 // certain times. 279 280 nsCOMPtr<nsPIDOMWindowOuter> windowToCheck; 281 if (windowRoot) { 282 windowToCheck = windowRoot->GetWindow(); 283 } else { 284 windowToCheck = privateWindow->GetPrivateRoot(); 285 } 286 287 nsCOMPtr<nsIContent> focusedContent; 288 if (windowToCheck) { 289 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow; 290 focusedContent = nsFocusManager::GetFocusedDescendant( 291 windowToCheck, nsFocusManager::eIncludeAllDescendants, 292 getter_AddRefs(focusedWindow)); 293 } 294 295 // If the focus is in an editable region, don't scroll. 296 if (focusedContent && focusedContent->IsEditable()) { 297 return NS_OK; 298 } 299 300 // If the focus is in a form control, don't scroll. 301 for (nsIContent* c = focusedContent; c; c = c->GetParent()) { 302 if (nsIFormControl::FromNode(c)) { 303 return NS_OK; 304 } 305 } 306 } 307 308 if (controller) { 309 controller->DoCommand(command.get()); 310 } 311 312 return NS_OK; 313 } 314 315 nsresult KeyEventHandler::DispatchXULKeyCommand(dom::Event* aEvent) { 316 nsCOMPtr<dom::Element> handlerElement = GetHandlerElement(); 317 NS_ENSURE_STATE(handlerElement); 318 if (handlerElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled, 319 nsGkAtoms::_true, eCaseMatters)) { 320 // Don't dispatch command events for disabled keys. 321 return NS_SUCCESS_DOM_NO_OPERATION; 322 } 323 324 aEvent->PreventDefault(); 325 326 // Copy the modifiers from the key event. 327 RefPtr<dom::KeyboardEvent> domKeyboardEvent = aEvent->AsKeyboardEvent(); 328 if (!domKeyboardEvent) { 329 NS_ERROR("Trying to execute a key handler for a non-key event!"); 330 return NS_ERROR_FAILURE; 331 } 332 333 // XXX We should use mozilla::Modifiers for supporting all modifiers. 334 335 bool isAlt = domKeyboardEvent->AltKey(); 336 bool isControl = domKeyboardEvent->CtrlKey(); 337 bool isShift = domKeyboardEvent->ShiftKey(); 338 bool isMeta = domKeyboardEvent->MetaKey(); 339 340 nsContentUtils::DispatchXULCommand(handlerElement, true, nullptr, nullptr, 341 isControl, isAlt, isShift, isMeta); 342 return NS_OK; 343 } 344 345 Modifiers KeyEventHandler::GetModifiers() const { 346 Modifiers modifiers = 0; 347 348 if (mKeyMask & cMeta) { 349 modifiers |= MODIFIER_META; 350 } 351 if (mKeyMask & cShift) { 352 modifiers |= MODIFIER_SHIFT; 353 } 354 if (mKeyMask & cAlt) { 355 modifiers |= MODIFIER_ALT; 356 } 357 if (mKeyMask & cControl) { 358 modifiers |= MODIFIER_CONTROL; 359 } 360 361 return modifiers; 362 } 363 364 Modifiers KeyEventHandler::GetModifiersMask() const { 365 Modifiers modifiersMask = 0; 366 367 if (mKeyMask & cMetaMask) { 368 modifiersMask |= MODIFIER_META; 369 } 370 if (mKeyMask & cShiftMask) { 371 modifiersMask |= MODIFIER_SHIFT; 372 } 373 if (mKeyMask & cAltMask) { 374 modifiersMask |= MODIFIER_ALT; 375 } 376 if (mKeyMask & cControlMask) { 377 modifiersMask |= MODIFIER_CONTROL; 378 } 379 380 return modifiersMask; 381 } 382 383 already_AddRefed<nsIController> KeyEventHandler::GetController( 384 dom::EventTarget* aTarget) { 385 if (!aTarget) { 386 return nullptr; 387 } 388 389 // XXX Fix this so there's a generic interface that describes controllers, 390 // This code should have no special knowledge of what objects might have 391 // controllers. 392 nsCOMPtr<nsIControllers> controllers; 393 if (nsIContent* targetContent = nsIContent::FromEventTarget(aTarget)) { 394 if (auto* xulElement = nsXULElement::FromNode(targetContent)) { 395 controllers = xulElement->GetExtantControllers(); 396 } else if (auto* htmlTextArea = 397 dom::HTMLTextAreaElement::FromNode(targetContent)) { 398 htmlTextArea->GetControllers(getter_AddRefs(controllers)); 399 } else if (auto* htmlInput = 400 dom::HTMLInputElement::FromNode(targetContent)) { 401 htmlInput->GetControllers(getter_AddRefs(controllers)); 402 } 403 } 404 405 if (!controllers) { 406 if (nsCOMPtr<nsPIDOMWindowOuter> domWindow = 407 nsPIDOMWindowOuter::FromEventTarget(aTarget)) { 408 domWindow->GetControllers(getter_AddRefs(controllers)); 409 } 410 } 411 412 // Return the first controller. 413 // XXX This code should be checking the command name and using supportscommand 414 // and iscommandenabled. 415 nsCOMPtr<nsIController> controller; 416 if (controllers) { 417 controllers->GetControllerAt(0, getter_AddRefs(controller)); 418 } 419 420 return controller.forget(); 421 } 422 423 bool KeyEventHandler::KeyEventMatched( 424 dom::KeyboardEvent* aDomKeyboardEvent, uint32_t aCharCode, 425 const IgnoreModifierState& aIgnoreModifierState) { 426 if (mDetail != -1) { 427 // Get the keycode or charcode of the key event. 428 uint32_t code; 429 430 if (mMisc) { 431 if (aCharCode) { 432 code = aCharCode; 433 } else { 434 code = aDomKeyboardEvent->CharCode(); 435 } 436 if (IS_IN_BMP(code)) { 437 code = ToLowerCase(char16_t(code)); 438 } 439 } else { 440 code = aDomKeyboardEvent->KeyCode(); 441 } 442 443 if (code != static_cast<uint32_t>(mDetail)) { 444 return false; 445 } 446 } 447 448 return ModifiersMatchMask(aDomKeyboardEvent, aIgnoreModifierState); 449 } 450 451 struct keyCodeData { 452 const char* str; 453 uint16_t strlength; 454 uint16_t keycode; 455 }; 456 457 // All of these must be uppercase, since the function below does 458 // case-insensitive comparison by converting to uppercase. 459 // XXX: be sure to check this periodically for new symbol additions! 460 static const keyCodeData gKeyCodes[] = { 461 462 #define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) \ 463 {#aDOMKeyName, sizeof(#aDOMKeyName) - 1, aDOMKeyCode}, 464 #include "mozilla/VirtualKeyCodeList.h" 465 #undef NS_DEFINE_VK 466 467 {nullptr, 0, 0}}; 468 469 int32_t KeyEventHandler::GetMatchingKeyCode(const nsAString& aKeyName) { 470 nsAutoCString keyName; 471 LossyCopyUTF16toASCII(aKeyName, keyName); 472 ToUpperCase(keyName); // We want case-insensitive comparison with data 473 // stored as uppercase. 474 475 uint32_t keyNameLength = keyName.Length(); 476 const char* keyNameStr = keyName.get(); 477 for (unsigned long i = 0; i < std::size(gKeyCodes) - 1; ++i) { 478 if (keyNameLength == gKeyCodes[i].strlength && 479 !nsCRT::strcmp(gKeyCodes[i].str, keyNameStr)) { 480 return gKeyCodes[i].keycode; 481 } 482 } 483 484 return 0; 485 } 486 487 int32_t KeyEventHandler::KeyToMask(uint32_t key) { 488 switch (key) { 489 case dom::KeyboardEvent_Binding::DOM_VK_META: 490 case dom::KeyboardEvent_Binding::DOM_VK_WIN: 491 return cMeta | cMetaMask; 492 493 case dom::KeyboardEvent_Binding::DOM_VK_ALT: 494 return cAlt | cAltMask; 495 496 case dom::KeyboardEvent_Binding::DOM_VK_CONTROL: 497 default: 498 return cControl | cControlMask; 499 } 500 } 501 502 // static 503 int32_t KeyEventHandler::AccelKeyMask() { 504 switch (WidgetInputEvent::AccelModifier()) { 505 case MODIFIER_ALT: 506 return KeyToMask(dom::KeyboardEvent_Binding::DOM_VK_ALT); 507 case MODIFIER_CONTROL: 508 return KeyToMask(dom::KeyboardEvent_Binding::DOM_VK_CONTROL); 509 case MODIFIER_META: 510 return KeyToMask(dom::KeyboardEvent_Binding::DOM_VK_META); 511 default: 512 MOZ_CRASH("Handle the new result of WidgetInputEvent::AccelModifier()"); 513 return 0; 514 } 515 } 516 517 void KeyEventHandler::GetEventType(nsAString& aEvent) { 518 nsCOMPtr<dom::Element> handlerElement = GetHandlerElement(); 519 if (!handlerElement) { 520 aEvent.Truncate(); 521 return; 522 } 523 handlerElement->GetAttr(nsGkAtoms::event, aEvent); 524 525 if (aEvent.IsEmpty() && mIsXULKey) { 526 // If no type is specified for a XUL <key> element, let's assume that we're 527 // "keypress". 528 aEvent.AssignLiteral("keypress"); 529 } 530 } 531 532 void KeyEventHandler::ConstructPrototype(dom::Element* aKeyElement, 533 const char16_t* aEvent, 534 const char16_t* aCommand, 535 const char16_t* aKeyCode, 536 const char16_t* aCharCode, 537 const char16_t* aModifiers) { 538 mDetail = -1; 539 mMisc = 0; 540 mKeyMask = 0; 541 nsAutoString modifiers; 542 543 if (mIsXULKey) { 544 nsWeakPtr weak = do_GetWeakReference(aKeyElement); 545 if (!weak) { 546 return; 547 } 548 weak.swap(mHandlerElement); 549 550 nsAutoString event; 551 GetEventType(event); 552 if (event.IsEmpty()) { 553 return; 554 } 555 mEventName = NS_Atomize(event); 556 557 aKeyElement->GetAttr(nsGkAtoms::modifiers, modifiers); 558 } else { 559 mCommand = ToNewUnicode(nsDependentString(aCommand)); 560 mEventName = NS_Atomize(aEvent); 561 modifiers = aModifiers; 562 } 563 564 BuildModifiers(modifiers); 565 566 nsAutoString key(aCharCode); 567 if (key.IsEmpty()) { 568 if (mIsXULKey) { 569 aKeyElement->GetAttr(nsGkAtoms::key, key); 570 if (key.IsEmpty()) { 571 aKeyElement->GetAttr(nsGkAtoms::charcode, key); 572 } 573 } 574 } 575 576 if (!key.IsEmpty()) { 577 if (mKeyMask == 0) { 578 mKeyMask = cAllModifiers; 579 } 580 ToLowerCase(key); 581 582 // We have a charcode. 583 mMisc = 1; 584 mDetail = key[0]; 585 const uint8_t GTK2Modifiers = cShift | cControl | cShiftMask | cControlMask; 586 if (mIsXULKey && (mKeyMask & GTK2Modifiers) == GTK2Modifiers && 587 modifiers.First() != char16_t(',') && 588 (mDetail == 'u' || mDetail == 'U')) { 589 ReportKeyConflict(key.get(), modifiers.get(), aKeyElement, 590 "GTK2Conflict2"); 591 } 592 const uint8_t WinModifiers = cControl | cAlt | cControlMask | cAltMask; 593 if (mIsXULKey && (mKeyMask & WinModifiers) == WinModifiers && 594 modifiers.First() != char16_t(',') && 595 (('A' <= mDetail && mDetail <= 'Z') || 596 ('a' <= mDetail && mDetail <= 'z'))) { 597 ReportKeyConflict(key.get(), modifiers.get(), aKeyElement, 598 "WinConflict2"); 599 } 600 } else { 601 key.Assign(aKeyCode); 602 if (mIsXULKey) { 603 aKeyElement->GetAttr(nsGkAtoms::keycode, key); 604 } 605 606 if (!key.IsEmpty()) { 607 if (mKeyMask == 0) { 608 mKeyMask = cAllModifiers; 609 } 610 mDetail = GetMatchingKeyCode(key); 611 } 612 } 613 } 614 615 void KeyEventHandler::BuildModifiers(nsAString& aModifiers) { 616 if (!aModifiers.IsEmpty()) { 617 mKeyMask = cAllModifiers; 618 char* str = ToNewCString(aModifiers); 619 char* newStr; 620 char* token = nsCRT::strtok(str, ", \t", &newStr); 621 while (token != nullptr) { 622 if (strcmp(token, "shift") == 0) { 623 mKeyMask |= cShift | cShiftMask; 624 } else if (strcmp(token, "alt") == 0) { 625 mKeyMask |= cAlt | cAltMask; 626 } else if (strcmp(token, "meta") == 0) { 627 mKeyMask |= cMeta | cMetaMask; 628 } else if (strcmp(token, "control") == 0) { 629 mKeyMask |= cControl | cControlMask; 630 } else if (strcmp(token, "accel") == 0) { 631 mKeyMask |= AccelKeyMask(); 632 } else if (strcmp(token, "access") == 0) { 633 mKeyMask |= KeyToMask(LookAndFeel::GetMenuAccessKey()); 634 } else if (strcmp(token, "any") == 0) { 635 mKeyMask &= ~(mKeyMask << 5); 636 } 637 638 token = nsCRT::strtok(newStr, ", \t", &newStr); 639 } 640 641 free(str); 642 } 643 } 644 645 void KeyEventHandler::ReportKeyConflict(const char16_t* aKey, 646 const char16_t* aModifiers, 647 dom::Element* aKeyElement, 648 const char* aMessageName) { 649 nsCOMPtr<dom::Document> doc = aKeyElement->OwnerDoc(); 650 651 nsAutoString id; 652 aKeyElement->GetAttr(nsGkAtoms::id, id); 653 AutoTArray<nsString, 3> params; 654 params.AppendElement(aKey); 655 params.AppendElement(aModifiers); 656 params.AppendElement(id); 657 nsContentUtils::ReportToConsole( 658 nsIScriptError::warningFlag, "Key dom::Event Handler"_ns, doc, 659 nsContentUtils::eDOM_PROPERTIES, aMessageName, params); 660 } 661 662 bool KeyEventHandler::ModifiersMatchMask( 663 dom::UIEvent* aEvent, const IgnoreModifierState& aIgnoreModifierState) { 664 WidgetInputEvent* inputEvent = aEvent->WidgetEventPtr()->AsInputEvent(); 665 NS_ENSURE_TRUE(inputEvent, false); 666 667 if ((mKeyMask & cMetaMask) && !aIgnoreModifierState.mMeta) { 668 if (inputEvent->IsMeta() != ((mKeyMask & cMeta) != 0)) { 669 return false; 670 } 671 } 672 673 if ((mKeyMask & cShiftMask) && !aIgnoreModifierState.mShift) { 674 if (inputEvent->IsShift() != ((mKeyMask & cShift) != 0)) { 675 return false; 676 } 677 } 678 679 if (mKeyMask & cAltMask) { 680 if (inputEvent->IsAlt() != ((mKeyMask & cAlt) != 0)) { 681 return false; 682 } 683 } 684 685 if (mKeyMask & cControlMask) { 686 if (inputEvent->IsControl() != ((mKeyMask & cControl) != 0)) { 687 return false; 688 } 689 } 690 691 return true; 692 } 693 694 size_t KeyEventHandler::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { 695 size_t n = 0; 696 for (const KeyEventHandler* handler = this; handler; 697 handler = handler->mNextHandler) { 698 n += aMallocSizeOf(handler); 699 if (!mIsXULKey) { 700 n += aMallocSizeOf(handler->mCommand); 701 } 702 } 703 return n; 704 } 705 706 } // namespace mozilla