Bug 1734943 [wpt PR 31170] - Correct scrolling contents cull rect, a=testonly
[gecko.git] / widget / WidgetEventImpl.cpp
blobee3f8fb4104da1277f30d546b3e382b84a9fabfd
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/BasicEvents.h"
7 #include "mozilla/ContentEvents.h"
8 #include "mozilla/EventStateManager.h"
9 #include "mozilla/InternalMutationEvent.h"
10 #include "mozilla/Maybe.h"
11 #include "mozilla/MiscEvents.h"
12 #include "mozilla/MouseEvents.h"
13 #include "mozilla/Preferences.h"
14 #include "mozilla/StaticPrefs_mousewheel.h"
15 #include "mozilla/StaticPrefs_ui.h"
16 #include "mozilla/TextEventDispatcher.h"
17 #include "mozilla/TextEvents.h"
18 #include "mozilla/TouchEvents.h"
19 #include "mozilla/WritingModes.h"
20 #include "mozilla/dom/KeyboardEventBinding.h"
21 #include "mozilla/dom/WheelEventBinding.h"
22 #include "nsCommandParams.h"
23 #include "nsContentUtils.h"
24 #include "nsIContent.h"
25 #include "nsIDragSession.h"
26 #include "nsPrintfCString.h"
28 #if defined(XP_WIN)
29 # include "npapi.h"
30 # include "WinUtils.h"
31 #endif // #if defined (XP_WIN)
33 #if defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
34 # include "NativeKeyBindings.h"
35 #endif // #if defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
37 namespace mozilla {
39 /******************************************************************************
40 * Global helper methods
41 ******************************************************************************/
43 const char* ToChar(EventMessage aEventMessage) {
44 switch (aEventMessage) {
45 #define NS_EVENT_MESSAGE(aMessage) \
46 case aMessage: \
47 return #aMessage;
49 #include "mozilla/EventMessageList.h"
51 #undef NS_EVENT_MESSAGE
52 default:
53 return "illegal event message";
57 const char* ToChar(EventClassID aEventClassID) {
58 switch (aEventClassID) {
59 #define NS_ROOT_EVENT_CLASS(aPrefix, aName) \
60 case eBasic##aName##Class: \
61 return "eBasic" #aName "Class";
63 #define NS_EVENT_CLASS(aPrefix, aName) \
64 case e##aName##Class: \
65 return "e" #aName "Class";
67 #include "mozilla/EventClassList.h"
69 #undef NS_EVENT_CLASS
70 #undef NS_ROOT_EVENT_CLASS
71 default:
72 return "illegal event class ID";
76 const nsCString ToString(KeyNameIndex aKeyNameIndex) {
77 if (aKeyNameIndex == KEY_NAME_INDEX_USE_STRING) {
78 return "USE_STRING"_ns;
80 nsAutoString keyName;
81 WidgetKeyboardEvent::GetDOMKeyName(aKeyNameIndex, keyName);
82 return NS_ConvertUTF16toUTF8(keyName);
85 const nsCString ToString(CodeNameIndex aCodeNameIndex) {
86 if (aCodeNameIndex == CODE_NAME_INDEX_USE_STRING) {
87 return "USE_STRING"_ns;
89 nsAutoString codeName;
90 WidgetKeyboardEvent::GetDOMCodeName(aCodeNameIndex, codeName);
91 return NS_ConvertUTF16toUTF8(codeName);
94 const char* ToChar(Command aCommand) {
95 if (aCommand == Command::DoNothing) {
96 return "CommandDoNothing";
99 switch (aCommand) {
100 #define NS_DEFINE_COMMAND(aName, aCommandStr) \
101 case Command::aName: \
102 return "Command::" #aName;
103 #define NS_DEFINE_COMMAND_WITH_PARAM(aName, aCommandStr, aParam) \
104 case Command::aName: \
105 return "Command::" #aName;
106 #define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName) \
107 case Command::aName: \
108 return "Command::" #aName;
110 #include "mozilla/CommandList.h"
112 #undef NS_DEFINE_COMMAND
113 #undef NS_DEFINE_COMMAND_WITH_PARAM
114 #undef NS_DEFINE_COMMAND_NO_EXEC_COMMAND
116 default:
117 return "illegal command value";
121 const nsCString GetDOMKeyCodeName(uint32_t aKeyCode) {
122 switch (aKeyCode) {
123 #define NS_DISALLOW_SAME_KEYCODE
124 #define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) \
125 case aDOMKeyCode: \
126 return nsLiteralCString(#aDOMKeyName);
128 #include "mozilla/VirtualKeyCodeList.h"
130 #undef NS_DEFINE_VK
131 #undef NS_DISALLOW_SAME_KEYCODE
133 default:
134 return nsPrintfCString("Invalid DOM keyCode (0x%08X)", aKeyCode);
138 bool IsValidRawTextRangeValue(RawTextRangeType aRawTextRangeType) {
139 switch (static_cast<TextRangeType>(aRawTextRangeType)) {
140 case TextRangeType::eUninitialized:
141 case TextRangeType::eCaret:
142 case TextRangeType::eRawClause:
143 case TextRangeType::eSelectedRawClause:
144 case TextRangeType::eConvertedClause:
145 case TextRangeType::eSelectedClause:
146 return true;
147 default:
148 return false;
152 RawTextRangeType ToRawTextRangeType(TextRangeType aTextRangeType) {
153 return static_cast<RawTextRangeType>(aTextRangeType);
156 TextRangeType ToTextRangeType(RawTextRangeType aRawTextRangeType) {
157 MOZ_ASSERT(IsValidRawTextRangeValue(aRawTextRangeType));
158 return static_cast<TextRangeType>(aRawTextRangeType);
161 const char* ToChar(TextRangeType aTextRangeType) {
162 switch (aTextRangeType) {
163 case TextRangeType::eUninitialized:
164 return "TextRangeType::eUninitialized";
165 case TextRangeType::eCaret:
166 return "TextRangeType::eCaret";
167 case TextRangeType::eRawClause:
168 return "TextRangeType::eRawClause";
169 case TextRangeType::eSelectedRawClause:
170 return "TextRangeType::eSelectedRawClause";
171 case TextRangeType::eConvertedClause:
172 return "TextRangeType::eConvertedClause";
173 case TextRangeType::eSelectedClause:
174 return "TextRangeType::eSelectedClause";
175 default:
176 return "Invalid TextRangeType";
180 SelectionType ToSelectionType(TextRangeType aTextRangeType) {
181 switch (aTextRangeType) {
182 case TextRangeType::eRawClause:
183 return SelectionType::eIMERawClause;
184 case TextRangeType::eSelectedRawClause:
185 return SelectionType::eIMESelectedRawClause;
186 case TextRangeType::eConvertedClause:
187 return SelectionType::eIMEConvertedClause;
188 case TextRangeType::eSelectedClause:
189 return SelectionType::eIMESelectedClause;
190 default:
191 MOZ_CRASH("TextRangeType is invalid");
192 return SelectionType::eNormal;
196 /******************************************************************************
197 * non class method implementation
198 ******************************************************************************/
200 static nsTHashMap<nsDepCharHashKey, Command>* sCommandHashtable = nullptr;
202 Command GetInternalCommand(const char* aCommandName,
203 const nsCommandParams* aCommandParams) {
204 if (!aCommandName) {
205 return Command::DoNothing;
208 // Special cases for "cmd_align". It's mapped to multiple internal commands
209 // with additional param. Therefore, we cannot handle it with the hashtable.
210 if (!strcmp(aCommandName, "cmd_align")) {
211 if (!aCommandParams) {
212 // Note that if this is called by EditorCommand::IsCommandEnabled(),
213 // it cannot set aCommandParams. So, don't warn in this case even though
214 // this is illegal case for DoCommandParams().
215 return Command::FormatJustify;
217 nsAutoCString cValue;
218 nsresult rv = aCommandParams->GetCString("state_attribute", cValue);
219 if (NS_FAILED(rv)) {
220 nsString value; // Avoid copying the string buffer with using nsString.
221 rv = aCommandParams->GetString("state_attribute", value);
222 if (NS_FAILED(rv)) {
223 return Command::FormatJustifyNone;
225 CopyUTF16toUTF8(value, cValue);
227 if (cValue.LowerCaseEqualsASCII("left")) {
228 return Command::FormatJustifyLeft;
230 if (cValue.LowerCaseEqualsASCII("right")) {
231 return Command::FormatJustifyRight;
233 if (cValue.LowerCaseEqualsASCII("center")) {
234 return Command::FormatJustifyCenter;
236 if (cValue.LowerCaseEqualsASCII("justify")) {
237 return Command::FormatJustifyFull;
239 if (cValue.IsEmpty()) {
240 return Command::FormatJustifyNone;
242 return Command::DoNothing;
245 if (!sCommandHashtable) {
246 sCommandHashtable = new nsTHashMap<nsDepCharHashKey, Command>();
247 #define NS_DEFINE_COMMAND(aName, aCommandStr) \
248 sCommandHashtable->InsertOrUpdate(#aCommandStr, Command::aName);
250 #define NS_DEFINE_COMMAND_WITH_PARAM(aName, aCommandStr, aParam)
252 #define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName)
254 #include "mozilla/CommandList.h"
256 #undef NS_DEFINE_COMMAND
257 #undef NS_DEFINE_COMMAND_WITH_PARAM
258 #undef NS_DEFINE_COMMAND_NO_EXEC_COMMAND
260 Command command = Command::DoNothing;
261 if (!sCommandHashtable->Get(aCommandName, &command)) {
262 return Command::DoNothing;
264 return command;
267 /******************************************************************************
268 * As*Event() implementation
269 ******************************************************************************/
271 #define NS_ROOT_EVENT_CLASS(aPrefix, aName)
272 #define NS_EVENT_CLASS(aPrefix, aName) \
273 aPrefix##aName* WidgetEvent::As##aName() { return nullptr; } \
275 const aPrefix##aName* WidgetEvent::As##aName() const { \
276 return const_cast<WidgetEvent*>(this)->As##aName(); \
279 #include "mozilla/EventClassList.h"
281 #undef NS_EVENT_CLASS
282 #undef NS_ROOT_EVENT_CLASS
284 /******************************************************************************
285 * mozilla::WidgetEvent
287 * Event struct type checking methods.
288 ******************************************************************************/
290 bool WidgetEvent::IsQueryContentEvent() const {
291 return mClass == eQueryContentEventClass;
294 bool WidgetEvent::IsSelectionEvent() const {
295 return mClass == eSelectionEventClass;
298 bool WidgetEvent::IsContentCommandEvent() const {
299 return mClass == eContentCommandEventClass;
302 /******************************************************************************
303 * mozilla::WidgetEvent
305 * Event message checking methods.
306 ******************************************************************************/
308 bool WidgetEvent::HasMouseEventMessage() const {
309 switch (mMessage) {
310 case eMouseDown:
311 case eMouseUp:
312 case eMouseClick:
313 case eMouseDoubleClick:
314 case eMouseAuxClick:
315 case eMouseEnterIntoWidget:
316 case eMouseExitFromWidget:
317 case eMouseActivate:
318 case eMouseOver:
319 case eMouseOut:
320 case eMouseHitTest:
321 case eMouseMove:
322 return true;
323 default:
324 return false;
328 bool WidgetEvent::HasDragEventMessage() const {
329 switch (mMessage) {
330 case eDragEnter:
331 case eDragOver:
332 case eDragExit:
333 case eDrag:
334 case eDragEnd:
335 case eDragStart:
336 case eDrop:
337 case eDragLeave:
338 return true;
339 default:
340 return false;
344 /* static */
345 bool WidgetEvent::IsKeyEventMessage(EventMessage aMessage) {
346 switch (aMessage) {
347 case eKeyDown:
348 case eKeyPress:
349 case eKeyUp:
350 case eKeyDownOnPlugin:
351 case eKeyUpOnPlugin:
352 case eAccessKeyNotFound:
353 return true;
354 default:
355 return false;
359 bool WidgetEvent::HasIMEEventMessage() const {
360 switch (mMessage) {
361 case eCompositionStart:
362 case eCompositionEnd:
363 case eCompositionUpdate:
364 case eCompositionChange:
365 case eCompositionCommitAsIs:
366 case eCompositionCommit:
367 return true;
368 default:
369 return false;
373 bool WidgetEvent::HasPluginActivationEventMessage() const {
374 return mMessage == ePluginActivate || mMessage == ePluginFocus;
377 /******************************************************************************
378 * mozilla::WidgetEvent
380 * Specific event checking methods.
381 ******************************************************************************/
383 bool WidgetEvent::CanBeSentToRemoteProcess() const {
384 // If this event is explicitly marked as shouldn't be sent to remote process,
385 // just return false.
386 if (IsCrossProcessForwardingStopped()) {
387 return false;
390 if (mClass == eKeyboardEventClass || mClass == eWheelEventClass) {
391 return true;
394 switch (mMessage) {
395 case eMouseDown:
396 case eMouseUp:
397 case eMouseMove:
398 case eContextMenu:
399 case eMouseEnterIntoWidget:
400 case eMouseExitFromWidget:
401 case eMouseTouchDrag:
402 case eTouchStart:
403 case eTouchMove:
404 case eTouchEnd:
405 case eTouchCancel:
406 case eDragOver:
407 case eDragExit:
408 case eDrop:
409 return true;
410 default:
411 return false;
415 bool WidgetEvent::WillBeSentToRemoteProcess() const {
416 // This event won't be posted to remote process if it's already explicitly
417 // stopped.
418 if (IsCrossProcessForwardingStopped()) {
419 return false;
422 // When mOriginalTarget is nullptr, this method shouldn't be used.
423 if (NS_WARN_IF(!mOriginalTarget)) {
424 return false;
427 nsCOMPtr<nsIContent> originalTarget = do_QueryInterface(mOriginalTarget);
428 return EventStateManager::IsTopLevelRemoteTarget(originalTarget);
431 bool WidgetEvent::IsIMERelatedEvent() const {
432 return HasIMEEventMessage() || IsQueryContentEvent() || IsSelectionEvent();
435 bool WidgetEvent::IsUsingCoordinates() const {
436 const WidgetMouseEvent* mouseEvent = AsMouseEvent();
437 if (mouseEvent) {
438 return !mouseEvent->IsContextMenuKeyEvent();
440 return !HasKeyEventMessage() && !IsIMERelatedEvent() &&
441 !HasPluginActivationEventMessage() && !IsContentCommandEvent();
444 bool WidgetEvent::IsTargetedAtFocusedWindow() const {
445 const WidgetMouseEvent* mouseEvent = AsMouseEvent();
446 if (mouseEvent) {
447 return mouseEvent->IsContextMenuKeyEvent();
449 return HasKeyEventMessage() || IsIMERelatedEvent() || IsContentCommandEvent();
452 bool WidgetEvent::IsTargetedAtFocusedContent() const {
453 const WidgetMouseEvent* mouseEvent = AsMouseEvent();
454 if (mouseEvent) {
455 return mouseEvent->IsContextMenuKeyEvent();
457 return HasKeyEventMessage() || IsIMERelatedEvent();
460 bool WidgetEvent::IsAllowedToDispatchDOMEvent() const {
461 switch (mClass) {
462 case eMouseEventClass:
463 if (mMessage == eMouseTouchDrag) {
464 return false;
466 [[fallthrough]];
467 case ePointerEventClass:
468 // We want synthesized mouse moves to cause mouseover and mouseout
469 // DOM events (EventStateManager::PreHandleEvent), but not mousemove
470 // DOM events.
471 // Synthesized button up events also do not cause DOM events because they
472 // do not have a reliable mRefPoint.
473 return AsMouseEvent()->mReason == WidgetMouseEvent::eReal;
475 case eWheelEventClass: {
476 // wheel event whose all delta values are zero by user pref applied, it
477 // shouldn't cause a DOM event.
478 const WidgetWheelEvent* wheelEvent = AsWheelEvent();
479 return wheelEvent->mDeltaX != 0.0 || wheelEvent->mDeltaY != 0.0 ||
480 wheelEvent->mDeltaZ != 0.0;
482 case eTouchEventClass:
483 return mMessage != eTouchPointerCancel;
484 // Following events are handled in EventStateManager, so, we don't need to
485 // dispatch DOM event for them into the DOM tree.
486 case eQueryContentEventClass:
487 case eSelectionEventClass:
488 case eContentCommandEventClass:
489 return false;
491 default:
492 return true;
496 bool WidgetEvent::IsAllowedToDispatchInSystemGroup() const {
497 // We don't expect to implement default behaviors with pointer events because
498 // if we do, prevent default on mouse events can't prevent default behaviors
499 // anymore.
500 return mClass != ePointerEventClass;
503 bool WidgetEvent::IsBlockedForFingerprintingResistance() const {
504 if (!nsContentUtils::ShouldResistFingerprinting()) {
505 return false;
508 switch (mClass) {
509 case eKeyboardEventClass: {
510 const WidgetKeyboardEvent* keyboardEvent = AsKeyboardEvent();
512 return (keyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_Alt ||
513 keyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_Shift ||
514 keyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_Control ||
515 keyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_AltGraph);
517 case ePointerEventClass: {
518 const WidgetPointerEvent* pointerEvent = AsPointerEvent();
520 // We suppress the pointer events if it is not primary for fingerprinting
521 // resistance. It is because of that we want to spoof any pointer event
522 // into a mouse pointer event and the mouse pointer event only has
523 // isPrimary as true.
524 return !pointerEvent->mIsPrimary;
526 default:
527 return false;
531 /******************************************************************************
532 * mozilla::WidgetEvent
534 * Misc methods.
535 ******************************************************************************/
537 static dom::EventTarget* GetTargetForDOMEvent(dom::EventTarget* aTarget) {
538 return aTarget ? aTarget->GetTargetForDOMEvent() : nullptr;
541 dom::EventTarget* WidgetEvent::GetDOMEventTarget() const {
542 return GetTargetForDOMEvent(mTarget);
545 dom::EventTarget* WidgetEvent::GetCurrentDOMEventTarget() const {
546 return GetTargetForDOMEvent(mCurrentTarget);
549 dom::EventTarget* WidgetEvent::GetOriginalDOMEventTarget() const {
550 if (mOriginalTarget) {
551 return GetTargetForDOMEvent(mOriginalTarget);
553 return GetDOMEventTarget();
556 void WidgetEvent::PreventDefault(bool aCalledByDefaultHandler,
557 nsIPrincipal* aPrincipal) {
558 if (mMessage == ePointerDown) {
559 if (aCalledByDefaultHandler) {
560 // Shouldn't prevent default on pointerdown by default handlers to stop
561 // firing legacy mouse events. Use MOZ_ASSERT to catch incorrect usages
562 // in debug builds.
563 MOZ_ASSERT(false);
564 return;
566 if (aPrincipal) {
567 nsAutoString addonId;
568 Unused << NS_WARN_IF(NS_FAILED(aPrincipal->GetAddonId(addonId)));
569 if (!addonId.IsEmpty()) {
570 // Ignore the case that it's called by a web extension.
571 return;
575 mFlags.PreventDefault(aCalledByDefaultHandler);
578 bool WidgetEvent::IsUserAction() const {
579 if (!IsTrusted()) {
580 return false;
582 // FYI: eMouseScrollEventClass and ePointerEventClass represent
583 // user action but they are synthesized events.
584 switch (mClass) {
585 case eKeyboardEventClass:
586 case eCompositionEventClass:
587 case eMouseScrollEventClass:
588 case eWheelEventClass:
589 case eGestureNotifyEventClass:
590 case eSimpleGestureEventClass:
591 case eTouchEventClass:
592 case eCommandEventClass:
593 case eContentCommandEventClass:
594 return true;
595 case eMouseEventClass:
596 case eDragEventClass:
597 case ePointerEventClass:
598 return AsMouseEvent()->IsReal();
599 default:
600 return false;
604 /******************************************************************************
605 * mozilla::WidgetInputEvent
606 ******************************************************************************/
608 /* static */
609 Modifier WidgetInputEvent::GetModifier(const nsAString& aDOMKeyName) {
610 if (aDOMKeyName.EqualsLiteral("Accel")) {
611 return AccelModifier();
613 KeyNameIndex keyNameIndex = WidgetKeyboardEvent::GetKeyNameIndex(aDOMKeyName);
614 return WidgetKeyboardEvent::GetModifierForKeyName(keyNameIndex);
617 /* static */
618 Modifier WidgetInputEvent::AccelModifier() {
619 static Modifier sAccelModifier = MODIFIER_NONE;
620 if (sAccelModifier == MODIFIER_NONE) {
621 switch (Preferences::GetInt("ui.key.accelKey", 0)) {
622 case dom::KeyboardEvent_Binding::DOM_VK_META:
623 sAccelModifier = MODIFIER_META;
624 break;
625 case dom::KeyboardEvent_Binding::DOM_VK_WIN:
626 sAccelModifier = MODIFIER_OS;
627 break;
628 case dom::KeyboardEvent_Binding::DOM_VK_ALT:
629 sAccelModifier = MODIFIER_ALT;
630 break;
631 case dom::KeyboardEvent_Binding::DOM_VK_CONTROL:
632 sAccelModifier = MODIFIER_CONTROL;
633 break;
634 default:
635 #ifdef XP_MACOSX
636 sAccelModifier = MODIFIER_META;
637 #else
638 sAccelModifier = MODIFIER_CONTROL;
639 #endif
640 break;
643 return sAccelModifier;
646 /******************************************************************************
647 * mozilla::WidgetMouseEvent (MouseEvents.h)
648 ******************************************************************************/
650 /* static */
651 bool WidgetMouseEvent::IsMiddleClickPasteEnabled() {
652 return Preferences::GetBool("middlemouse.paste", false);
655 #ifdef DEBUG
656 void WidgetMouseEvent::AssertContextMenuEventButtonConsistency() const {
657 if (mMessage != eContextMenu) {
658 return;
661 if (mContextMenuTrigger == eNormal) {
662 NS_WARNING_ASSERTION(mButton == MouseButton::eSecondary,
663 "eContextMenu events with eNormal trigger should use "
664 "secondary mouse button");
665 } else {
666 NS_WARNING_ASSERTION(mButton == MouseButton::ePrimary,
667 "eContextMenu events with non-eNormal trigger should "
668 "use primary mouse button");
671 if (mContextMenuTrigger == eControlClick) {
672 NS_WARNING_ASSERTION(IsControl(),
673 "eContextMenu events with eControlClick trigger "
674 "should return true from IsControl()");
677 #endif
679 /******************************************************************************
680 * mozilla::WidgetDragEvent (MouseEvents.h)
681 ******************************************************************************/
683 void WidgetDragEvent::InitDropEffectForTests() {
684 MOZ_ASSERT(mFlags.mIsSynthesizedForTests);
686 nsCOMPtr<nsIDragSession> session = nsContentUtils::GetDragSession();
687 if (NS_WARN_IF(!session)) {
688 return;
691 uint32_t effectAllowed = session->GetEffectAllowedForTests();
692 uint32_t desiredDropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
693 #ifdef XP_MACOSX
694 if (IsAlt()) {
695 desiredDropEffect = IsMeta() ? nsIDragService::DRAGDROP_ACTION_LINK
696 : nsIDragService::DRAGDROP_ACTION_COPY;
698 #else
699 // On Linux, we know user's intention from API, but we should use
700 // same modifiers as Windows for tests because GNOME on Ubuntu use
701 // them and that makes each test simpler.
702 if (IsControl()) {
703 desiredDropEffect = IsShift() ? nsIDragService::DRAGDROP_ACTION_LINK
704 : nsIDragService::DRAGDROP_ACTION_COPY;
705 } else if (IsShift()) {
706 desiredDropEffect = nsIDragService::DRAGDROP_ACTION_MOVE;
708 #endif // #ifdef XP_MACOSX #else
709 // First, use modifier state for preferring action which is explicitly
710 // specified by the synthesizer.
711 if (!(desiredDropEffect &= effectAllowed)) {
712 // Otherwise, use an action which is allowed at starting the session.
713 desiredDropEffect = effectAllowed;
715 if (desiredDropEffect & nsIDragService::DRAGDROP_ACTION_MOVE) {
716 session->SetDragAction(nsIDragService::DRAGDROP_ACTION_MOVE);
717 } else if (desiredDropEffect & nsIDragService::DRAGDROP_ACTION_COPY) {
718 session->SetDragAction(nsIDragService::DRAGDROP_ACTION_COPY);
719 } else if (desiredDropEffect & nsIDragService::DRAGDROP_ACTION_LINK) {
720 session->SetDragAction(nsIDragService::DRAGDROP_ACTION_LINK);
721 } else {
722 session->SetDragAction(nsIDragService::DRAGDROP_ACTION_NONE);
726 /******************************************************************************
727 * mozilla::WidgetWheelEvent (MouseEvents.h)
728 ******************************************************************************/
730 /* static */
731 double WidgetWheelEvent::ComputeOverriddenDelta(double aDelta,
732 bool aIsForVertical) {
733 if (!StaticPrefs::mousewheel_system_scroll_override_enabled()) {
734 return aDelta;
736 int32_t intFactor =
737 aIsForVertical
738 ? StaticPrefs::mousewheel_system_scroll_override_vertical_factor()
739 : StaticPrefs::mousewheel_system_scroll_override_horizontal_factor();
740 // Making the scroll speed slower doesn't make sense. So, ignore odd factor
741 // which is less than 1.0.
742 if (intFactor <= 100) {
743 return aDelta;
745 double factor = static_cast<double>(intFactor) / 100;
746 return aDelta * factor;
749 double WidgetWheelEvent::OverriddenDeltaX() const {
750 if (!mAllowToOverrideSystemScrollSpeed ||
751 mDeltaMode != dom::WheelEvent_Binding::DOM_DELTA_LINE ||
752 mCustomizedByUserPrefs) {
753 return mDeltaX;
755 return ComputeOverriddenDelta(mDeltaX, false);
758 double WidgetWheelEvent::OverriddenDeltaY() const {
759 if (!mAllowToOverrideSystemScrollSpeed ||
760 mDeltaMode != dom::WheelEvent_Binding::DOM_DELTA_LINE ||
761 mCustomizedByUserPrefs) {
762 return mDeltaY;
764 return ComputeOverriddenDelta(mDeltaY, true);
767 /******************************************************************************
768 * mozilla::WidgetKeyboardEvent (TextEvents.h)
769 ******************************************************************************/
771 #define NS_DEFINE_KEYNAME(aCPPName, aDOMKeyName) (u"" aDOMKeyName),
772 const char16_t* const WidgetKeyboardEvent::kKeyNames[] = {
773 #include "mozilla/KeyNameList.h"
775 #undef NS_DEFINE_KEYNAME
777 #define NS_DEFINE_PHYSICAL_KEY_CODE_NAME(aCPPName, aDOMCodeName) \
778 (u"" aDOMCodeName),
779 const char16_t* const WidgetKeyboardEvent::kCodeNames[] = {
780 #include "mozilla/PhysicalKeyCodeNameList.h"
782 #undef NS_DEFINE_PHYSICAL_KEY_CODE_NAME
784 WidgetKeyboardEvent::KeyNameIndexHashtable*
785 WidgetKeyboardEvent::sKeyNameIndexHashtable = nullptr;
786 WidgetKeyboardEvent::CodeNameIndexHashtable*
787 WidgetKeyboardEvent::sCodeNameIndexHashtable = nullptr;
789 void WidgetKeyboardEvent::InitAllEditCommands(
790 const Maybe<WritingMode>& aWritingMode) {
791 // If this event is synthesized for tests, we don't need to retrieve the
792 // command via the main process. So, we don't need widget and can trust
793 // the event.
794 if (!mFlags.mIsSynthesizedForTests) {
795 // If the event was created without widget, e.g., created event in chrome
796 // script, this shouldn't execute native key bindings.
797 if (NS_WARN_IF(!mWidget)) {
798 return;
801 // This event should be trusted event here and we shouldn't expose native
802 // key binding information to web contents with untrusted events.
803 if (NS_WARN_IF(!IsTrusted())) {
804 return;
807 MOZ_ASSERT(
808 XRE_IsParentProcess(),
809 "It's too expensive to retrieve all edit commands from remote process");
810 MOZ_ASSERT(!AreAllEditCommandsInitialized(),
811 "Shouldn't be called two or more times");
814 DebugOnly<bool> okIgnored = InitEditCommandsFor(
815 nsIWidget::NativeKeyBindingsForSingleLineEditor, aWritingMode);
816 NS_WARNING_ASSERTION(
817 okIgnored,
818 "InitEditCommandsFor(nsIWidget::NativeKeyBindingsForSingleLineEditor) "
819 "failed, but ignored");
820 okIgnored = InitEditCommandsFor(
821 nsIWidget::NativeKeyBindingsForMultiLineEditor, aWritingMode);
822 NS_WARNING_ASSERTION(
823 okIgnored,
824 "InitEditCommandsFor(nsIWidget::NativeKeyBindingsForMultiLineEditor) "
825 "failed, but ignored");
826 okIgnored = InitEditCommandsFor(nsIWidget::NativeKeyBindingsForRichTextEditor,
827 aWritingMode);
828 NS_WARNING_ASSERTION(
829 okIgnored,
830 "InitEditCommandsFor(nsIWidget::NativeKeyBindingsForRichTextEditor) "
831 "failed, but ignored");
834 bool WidgetKeyboardEvent::InitEditCommandsFor(
835 nsIWidget::NativeKeyBindingsType aType,
836 const Maybe<WritingMode>& aWritingMode) {
837 bool& initialized = IsEditCommandsInitializedRef(aType);
838 if (initialized) {
839 return true;
841 nsTArray<CommandInt>& commands = EditCommandsRef(aType);
843 // If this event is synthesized for tests, we shouldn't access customized
844 // shortcut settings of the environment. Therefore, we don't need to check
845 // whether `widget` is set or not. And we can treat synthesized events are
846 // always trusted.
847 if (mFlags.mIsSynthesizedForTests) {
848 MOZ_DIAGNOSTIC_ASSERT(IsTrusted());
849 #if defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
850 // TODO: We should implement `NativeKeyBindings` for Windows and Android
851 // too in bug 1301497 for getting rid of the #if.
852 widget::NativeKeyBindings::GetEditCommandsForTests(aType, *this,
853 aWritingMode, commands);
854 #endif
855 initialized = true;
856 return true;
859 if (NS_WARN_IF(!mWidget) || NS_WARN_IF(!IsTrusted())) {
860 return false;
862 // `nsIWidget::GetEditCommands()` will retrieve `WritingMode` at selection
863 // again, but it should be almost zero-cost since `TextEventDispatcher`
864 // caches the value.
865 nsCOMPtr<nsIWidget> widget = mWidget;
866 initialized = widget->GetEditCommands(aType, *this, commands);
867 return initialized;
870 bool WidgetKeyboardEvent::ExecuteEditCommands(
871 nsIWidget::NativeKeyBindingsType aType, DoCommandCallback aCallback,
872 void* aCallbackData) {
873 // If the event was created without widget, e.g., created event in chrome
874 // script, this shouldn't execute native key bindings.
875 if (NS_WARN_IF(!mWidget)) {
876 return false;
879 // This event should be trusted event here and we shouldn't expose native
880 // key binding information to web contents with untrusted events.
881 if (NS_WARN_IF(!IsTrusted())) {
882 return false;
885 if (!IsEditCommandsInitializedRef(aType)) {
886 Maybe<WritingMode> writingMode;
887 if (RefPtr<widget::TextEventDispatcher> textEventDispatcher =
888 mWidget->GetTextEventDispatcher()) {
889 writingMode = textEventDispatcher->MaybeWritingModeAtSelection();
891 if (NS_WARN_IF(!InitEditCommandsFor(aType, writingMode))) {
892 return false;
896 const nsTArray<CommandInt>& commands = EditCommandsRef(aType);
897 if (commands.IsEmpty()) {
898 return false;
901 for (CommandInt command : commands) {
902 aCallback(static_cast<Command>(command), aCallbackData);
904 return true;
907 bool WidgetKeyboardEvent::ShouldCauseKeypressEvents() const {
908 // Currently, we don't dispatch keypress events of modifier keys and
909 // dead keys.
910 switch (mKeyNameIndex) {
911 case KEY_NAME_INDEX_Alt:
912 case KEY_NAME_INDEX_AltGraph:
913 case KEY_NAME_INDEX_CapsLock:
914 case KEY_NAME_INDEX_Control:
915 case KEY_NAME_INDEX_Fn:
916 case KEY_NAME_INDEX_FnLock:
917 // case KEY_NAME_INDEX_Hyper:
918 case KEY_NAME_INDEX_Meta:
919 case KEY_NAME_INDEX_NumLock:
920 case KEY_NAME_INDEX_OS:
921 case KEY_NAME_INDEX_ScrollLock:
922 case KEY_NAME_INDEX_Shift:
923 // case KEY_NAME_INDEX_Super:
924 case KEY_NAME_INDEX_Symbol:
925 case KEY_NAME_INDEX_SymbolLock:
926 case KEY_NAME_INDEX_Dead:
927 return false;
928 default:
929 return true;
933 static bool HasASCIIDigit(const ShortcutKeyCandidateArray& aCandidates) {
934 for (uint32_t i = 0; i < aCandidates.Length(); ++i) {
935 uint32_t ch = aCandidates[i].mCharCode;
936 if (ch >= '0' && ch <= '9') return true;
938 return false;
941 static bool CharsCaseInsensitiveEqual(uint32_t aChar1, uint32_t aChar2) {
942 return aChar1 == aChar2 || (IS_IN_BMP(aChar1) && IS_IN_BMP(aChar2) &&
943 ToLowerCase(static_cast<char16_t>(aChar1)) ==
944 ToLowerCase(static_cast<char16_t>(aChar2)));
947 static bool IsCaseChangeableChar(uint32_t aChar) {
948 return IS_IN_BMP(aChar) && ToLowerCase(static_cast<char16_t>(aChar)) !=
949 ToUpperCase(static_cast<char16_t>(aChar));
952 void WidgetKeyboardEvent::GetShortcutKeyCandidates(
953 ShortcutKeyCandidateArray& aCandidates) const {
954 MOZ_ASSERT(aCandidates.IsEmpty(), "aCandidates must be empty");
956 // ShortcutKeyCandidate::mCharCode is a candidate charCode.
957 // ShortcutKeyCandidate::mIgnoreShift means the mCharCode should be tried to
958 // execute a command with/without shift key state. If this is TRUE, the
959 // shifted key state should be ignored. Otherwise, don't ignore the state.
960 // the priority of the charCodes are (shift key is not pressed):
961 // 0: PseudoCharCode()/false,
962 // 1: unshiftedCharCodes[0]/false, 2: unshiftedCharCodes[1]/false...
963 // the priority of the charCodes are (shift key is pressed):
964 // 0: PseudoCharCode()/false,
965 // 1: shiftedCharCodes[0]/false, 2: shiftedCharCodes[0]/true,
966 // 3: shiftedCharCodes[1]/false, 4: shiftedCharCodes[1]/true...
967 uint32_t pseudoCharCode = PseudoCharCode();
968 if (pseudoCharCode) {
969 ShortcutKeyCandidate key(pseudoCharCode, false);
970 aCandidates.AppendElement(key);
973 uint32_t len = mAlternativeCharCodes.Length();
974 if (!IsShift()) {
975 for (uint32_t i = 0; i < len; ++i) {
976 uint32_t ch = mAlternativeCharCodes[i].mUnshiftedCharCode;
977 if (!ch || ch == pseudoCharCode) {
978 continue;
980 ShortcutKeyCandidate key(ch, false);
981 aCandidates.AppendElement(key);
983 // If unshiftedCharCodes doesn't have numeric but shiftedCharCode has it,
984 // this keyboard layout is AZERTY or similar layout, probably.
985 // In this case, Accel+[0-9] should be accessible without shift key.
986 // However, the priority should be lowest.
987 if (!HasASCIIDigit(aCandidates)) {
988 for (uint32_t i = 0; i < len; ++i) {
989 uint32_t ch = mAlternativeCharCodes[i].mShiftedCharCode;
990 if (ch >= '0' && ch <= '9') {
991 ShortcutKeyCandidate key(ch, false);
992 aCandidates.AppendElement(key);
993 break;
997 } else {
998 for (uint32_t i = 0; i < len; ++i) {
999 uint32_t ch = mAlternativeCharCodes[i].mShiftedCharCode;
1000 if (!ch) {
1001 continue;
1004 if (ch != pseudoCharCode) {
1005 ShortcutKeyCandidate key(ch, false);
1006 aCandidates.AppendElement(key);
1009 // If the char is an alphabet, the shift key state should not be
1010 // ignored. E.g., Ctrl+Shift+C should not execute Ctrl+C.
1012 // And checking the charCode is same as unshiftedCharCode too.
1013 // E.g., for Ctrl+Shift+(Plus of Numpad) should not run Ctrl+Plus.
1014 uint32_t unshiftCh = mAlternativeCharCodes[i].mUnshiftedCharCode;
1015 if (CharsCaseInsensitiveEqual(ch, unshiftCh)) {
1016 continue;
1019 // On the Hebrew keyboard layout on Windows, the unshifted char is a
1020 // localized character but the shifted char is a Latin alphabet,
1021 // then, we should not execute without the shift state. See bug 433192.
1022 if (IsCaseChangeableChar(ch)) {
1023 continue;
1026 // Setting the alternative charCode candidates for retry without shift
1027 // key state only when the shift key is pressed.
1028 ShortcutKeyCandidate key(ch, true);
1029 aCandidates.AppendElement(key);
1033 // Special case for "Space" key. With some keyboard layouts, "Space" with
1034 // or without Shift key causes non-ASCII space. For such keyboard layouts,
1035 // we should guarantee that the key press works as an ASCII white space key
1036 // press. However, if the space key is assigned to a function key, it
1037 // shouldn't work as a space key.
1038 if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING &&
1039 mCodeNameIndex == CODE_NAME_INDEX_Space && pseudoCharCode != ' ') {
1040 ShortcutKeyCandidate spaceKey(' ', false);
1041 aCandidates.AppendElement(spaceKey);
1045 void WidgetKeyboardEvent::GetAccessKeyCandidates(
1046 nsTArray<uint32_t>& aCandidates) const {
1047 MOZ_ASSERT(aCandidates.IsEmpty(), "aCandidates must be empty");
1049 // return the lower cased charCode candidates for access keys.
1050 // the priority of the charCodes are:
1051 // 0: charCode, 1: unshiftedCharCodes[0], 2: shiftedCharCodes[0]
1052 // 3: unshiftedCharCodes[1], 4: shiftedCharCodes[1],...
1053 uint32_t pseudoCharCode = PseudoCharCode();
1054 if (pseudoCharCode) {
1055 uint32_t ch = pseudoCharCode;
1056 if (IS_IN_BMP(ch)) {
1057 ch = ToLowerCase(static_cast<char16_t>(ch));
1059 aCandidates.AppendElement(ch);
1061 for (uint32_t i = 0; i < mAlternativeCharCodes.Length(); ++i) {
1062 uint32_t ch[2] = {mAlternativeCharCodes[i].mUnshiftedCharCode,
1063 mAlternativeCharCodes[i].mShiftedCharCode};
1064 for (uint32_t j = 0; j < 2; ++j) {
1065 if (!ch[j]) {
1066 continue;
1068 if (IS_IN_BMP(ch[j])) {
1069 ch[j] = ToLowerCase(static_cast<char16_t>(ch[j]));
1071 // Don't append the charcode that was already appended.
1072 if (aCandidates.IndexOf(ch[j]) == aCandidates.NoIndex) {
1073 aCandidates.AppendElement(ch[j]);
1077 // Special case for "Space" key. With some keyboard layouts, "Space" with
1078 // or without Shift key causes non-ASCII space. For such keyboard layouts,
1079 // we should guarantee that the key press works as an ASCII white space key
1080 // press. However, if the space key is assigned to a function key, it
1081 // shouldn't work as a space key.
1082 if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING &&
1083 mCodeNameIndex == CODE_NAME_INDEX_Space && pseudoCharCode != ' ') {
1084 aCandidates.AppendElement(' ');
1088 // mask values for ui.key.chromeAccess and ui.key.contentAccess
1089 #define NS_MODIFIER_SHIFT 1
1090 #define NS_MODIFIER_CONTROL 2
1091 #define NS_MODIFIER_ALT 4
1092 #define NS_MODIFIER_META 8
1093 #define NS_MODIFIER_OS 16
1095 static Modifiers PrefFlagsToModifiers(int32_t aPrefFlags) {
1096 Modifiers result = 0;
1097 if (aPrefFlags & NS_MODIFIER_SHIFT) {
1098 result |= MODIFIER_SHIFT;
1100 if (aPrefFlags & NS_MODIFIER_CONTROL) {
1101 result |= MODIFIER_CONTROL;
1103 if (aPrefFlags & NS_MODIFIER_ALT) {
1104 result |= MODIFIER_ALT;
1106 if (aPrefFlags & NS_MODIFIER_META) {
1107 result |= MODIFIER_META;
1109 if (aPrefFlags & NS_MODIFIER_OS) {
1110 result |= MODIFIER_OS;
1112 return result;
1115 bool WidgetKeyboardEvent::ModifiersMatchWithAccessKey(
1116 AccessKeyType aType) const {
1117 if (!ModifiersForAccessKeyMatching()) {
1118 return false;
1120 return ModifiersForAccessKeyMatching() == AccessKeyModifiers(aType);
1123 Modifiers WidgetKeyboardEvent::ModifiersForAccessKeyMatching() const {
1124 static const Modifiers kModifierMask = MODIFIER_SHIFT | MODIFIER_CONTROL |
1125 MODIFIER_ALT | MODIFIER_META |
1126 MODIFIER_OS;
1127 return mModifiers & kModifierMask;
1130 /* static */
1131 Modifiers WidgetKeyboardEvent::AccessKeyModifiers(AccessKeyType aType) {
1132 switch (StaticPrefs::ui_key_generalAccessKey()) {
1133 case -1:
1134 break; // use the individual prefs
1135 case NS_VK_SHIFT:
1136 return MODIFIER_SHIFT;
1137 case NS_VK_CONTROL:
1138 return MODIFIER_CONTROL;
1139 case NS_VK_ALT:
1140 return MODIFIER_ALT;
1141 case NS_VK_META:
1142 return MODIFIER_META;
1143 case NS_VK_WIN:
1144 return MODIFIER_OS;
1145 default:
1146 return MODIFIER_NONE;
1149 switch (aType) {
1150 case AccessKeyType::eChrome:
1151 return PrefFlagsToModifiers(StaticPrefs::ui_key_chromeAccess());
1152 case AccessKeyType::eContent:
1153 return PrefFlagsToModifiers(StaticPrefs::ui_key_contentAccess());
1154 default:
1155 return MODIFIER_NONE;
1159 /* static */
1160 void WidgetKeyboardEvent::Shutdown() {
1161 delete sKeyNameIndexHashtable;
1162 sKeyNameIndexHashtable = nullptr;
1163 delete sCodeNameIndexHashtable;
1164 sCodeNameIndexHashtable = nullptr;
1165 // Although sCommandHashtable is not a member of WidgetKeyboardEvent, but
1166 // let's delete it here since we need to do it at same time.
1167 delete sCommandHashtable;
1168 sCommandHashtable = nullptr;
1171 /* static */
1172 void WidgetKeyboardEvent::GetDOMKeyName(KeyNameIndex aKeyNameIndex,
1173 nsAString& aKeyName) {
1174 if (aKeyNameIndex >= KEY_NAME_INDEX_USE_STRING) {
1175 aKeyName.Truncate();
1176 return;
1179 MOZ_RELEASE_ASSERT(
1180 static_cast<size_t>(aKeyNameIndex) < ArrayLength(kKeyNames),
1181 "Illegal key enumeration value");
1182 aKeyName = kKeyNames[aKeyNameIndex];
1185 /* static */
1186 void WidgetKeyboardEvent::GetDOMCodeName(CodeNameIndex aCodeNameIndex,
1187 nsAString& aCodeName) {
1188 if (aCodeNameIndex >= CODE_NAME_INDEX_USE_STRING) {
1189 aCodeName.Truncate();
1190 return;
1193 MOZ_RELEASE_ASSERT(
1194 static_cast<size_t>(aCodeNameIndex) < ArrayLength(kCodeNames),
1195 "Illegal physical code enumeration value");
1196 aCodeName = kCodeNames[aCodeNameIndex];
1199 /* static */
1200 KeyNameIndex WidgetKeyboardEvent::GetKeyNameIndex(const nsAString& aKeyValue) {
1201 if (!sKeyNameIndexHashtable) {
1202 sKeyNameIndexHashtable = new KeyNameIndexHashtable(ArrayLength(kKeyNames));
1203 for (size_t i = 0; i < ArrayLength(kKeyNames); i++) {
1204 sKeyNameIndexHashtable->InsertOrUpdate(nsDependentString(kKeyNames[i]),
1205 static_cast<KeyNameIndex>(i));
1208 return sKeyNameIndexHashtable->MaybeGet(aKeyValue).valueOr(
1209 KEY_NAME_INDEX_USE_STRING);
1212 /* static */
1213 CodeNameIndex WidgetKeyboardEvent::GetCodeNameIndex(
1214 const nsAString& aCodeValue) {
1215 if (!sCodeNameIndexHashtable) {
1216 sCodeNameIndexHashtable =
1217 new CodeNameIndexHashtable(ArrayLength(kCodeNames));
1218 for (size_t i = 0; i < ArrayLength(kCodeNames); i++) {
1219 sCodeNameIndexHashtable->InsertOrUpdate(nsDependentString(kCodeNames[i]),
1220 static_cast<CodeNameIndex>(i));
1223 return sCodeNameIndexHashtable->MaybeGet(aCodeValue)
1224 .valueOr(CODE_NAME_INDEX_USE_STRING);
1227 /* static */
1228 uint32_t WidgetKeyboardEvent::GetFallbackKeyCodeOfPunctuationKey(
1229 CodeNameIndex aCodeNameIndex) {
1230 switch (aCodeNameIndex) {
1231 case CODE_NAME_INDEX_Semicolon: // VK_OEM_1 on Windows
1232 return dom::KeyboardEvent_Binding::DOM_VK_SEMICOLON;
1233 case CODE_NAME_INDEX_Equal: // VK_OEM_PLUS on Windows
1234 return dom::KeyboardEvent_Binding::DOM_VK_EQUALS;
1235 case CODE_NAME_INDEX_Comma: // VK_OEM_COMMA on Windows
1236 return dom::KeyboardEvent_Binding::DOM_VK_COMMA;
1237 case CODE_NAME_INDEX_Minus: // VK_OEM_MINUS on Windows
1238 return dom::KeyboardEvent_Binding::DOM_VK_HYPHEN_MINUS;
1239 case CODE_NAME_INDEX_Period: // VK_OEM_PERIOD on Windows
1240 return dom::KeyboardEvent_Binding::DOM_VK_PERIOD;
1241 case CODE_NAME_INDEX_Slash: // VK_OEM_2 on Windows
1242 return dom::KeyboardEvent_Binding::DOM_VK_SLASH;
1243 case CODE_NAME_INDEX_Backquote: // VK_OEM_3 on Windows
1244 return dom::KeyboardEvent_Binding::DOM_VK_BACK_QUOTE;
1245 case CODE_NAME_INDEX_BracketLeft: // VK_OEM_4 on Windows
1246 return dom::KeyboardEvent_Binding::DOM_VK_OPEN_BRACKET;
1247 case CODE_NAME_INDEX_Backslash: // VK_OEM_5 on Windows
1248 return dom::KeyboardEvent_Binding::DOM_VK_BACK_SLASH;
1249 case CODE_NAME_INDEX_BracketRight: // VK_OEM_6 on Windows
1250 return dom::KeyboardEvent_Binding::DOM_VK_CLOSE_BRACKET;
1251 case CODE_NAME_INDEX_Quote: // VK_OEM_7 on Windows
1252 return dom::KeyboardEvent_Binding::DOM_VK_QUOTE;
1253 case CODE_NAME_INDEX_IntlBackslash: // VK_OEM_5 on Windows (ABNT, etc)
1254 case CODE_NAME_INDEX_IntlYen: // VK_OEM_5 on Windows (JIS)
1255 case CODE_NAME_INDEX_IntlRo: // VK_OEM_102 on Windows
1256 return dom::KeyboardEvent_Binding::DOM_VK_BACK_SLASH;
1257 default:
1258 return 0;
1262 /* static */ const char* WidgetKeyboardEvent::GetCommandStr(Command aCommand) {
1263 #define NS_DEFINE_COMMAND(aName, aCommandStr) , #aCommandStr
1264 #define NS_DEFINE_COMMAND_WITH_PARAM(aName, aCommandStr, aParam) , #aCommandStr
1265 #define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName) , ""
1266 static const char* const kCommands[] = {
1267 "" // DoNothing
1268 #include "mozilla/CommandList.h"
1270 #undef NS_DEFINE_COMMAND
1271 #undef NS_DEFINE_COMMAND_WITH_PARAM
1272 #undef NS_DEFINE_COMMAND_NO_EXEC_COMMAND
1274 MOZ_RELEASE_ASSERT(static_cast<size_t>(aCommand) < ArrayLength(kCommands),
1275 "Illegal command enumeration value");
1276 return kCommands[static_cast<CommandInt>(aCommand)];
1279 /* static */
1280 uint32_t WidgetKeyboardEvent::ComputeLocationFromCodeValue(
1281 CodeNameIndex aCodeNameIndex) {
1282 // Following commented out cases are not defined in PhysicalKeyCodeNameList.h
1283 // but are defined by D3E spec. So, they should be uncommented when the
1284 // code values are defined in the header.
1285 switch (aCodeNameIndex) {
1286 case CODE_NAME_INDEX_AltLeft:
1287 case CODE_NAME_INDEX_ControlLeft:
1288 case CODE_NAME_INDEX_OSLeft:
1289 case CODE_NAME_INDEX_ShiftLeft:
1290 return eKeyLocationLeft;
1291 case CODE_NAME_INDEX_AltRight:
1292 case CODE_NAME_INDEX_ControlRight:
1293 case CODE_NAME_INDEX_OSRight:
1294 case CODE_NAME_INDEX_ShiftRight:
1295 return eKeyLocationRight;
1296 case CODE_NAME_INDEX_Numpad0:
1297 case CODE_NAME_INDEX_Numpad1:
1298 case CODE_NAME_INDEX_Numpad2:
1299 case CODE_NAME_INDEX_Numpad3:
1300 case CODE_NAME_INDEX_Numpad4:
1301 case CODE_NAME_INDEX_Numpad5:
1302 case CODE_NAME_INDEX_Numpad6:
1303 case CODE_NAME_INDEX_Numpad7:
1304 case CODE_NAME_INDEX_Numpad8:
1305 case CODE_NAME_INDEX_Numpad9:
1306 case CODE_NAME_INDEX_NumpadAdd:
1307 case CODE_NAME_INDEX_NumpadBackspace:
1308 case CODE_NAME_INDEX_NumpadClear:
1309 case CODE_NAME_INDEX_NumpadClearEntry:
1310 case CODE_NAME_INDEX_NumpadComma:
1311 case CODE_NAME_INDEX_NumpadDecimal:
1312 case CODE_NAME_INDEX_NumpadDivide:
1313 case CODE_NAME_INDEX_NumpadEnter:
1314 case CODE_NAME_INDEX_NumpadEqual:
1315 case CODE_NAME_INDEX_NumpadMemoryAdd:
1316 case CODE_NAME_INDEX_NumpadMemoryClear:
1317 case CODE_NAME_INDEX_NumpadMemoryRecall:
1318 case CODE_NAME_INDEX_NumpadMemoryStore:
1319 case CODE_NAME_INDEX_NumpadMemorySubtract:
1320 case CODE_NAME_INDEX_NumpadMultiply:
1321 case CODE_NAME_INDEX_NumpadParenLeft:
1322 case CODE_NAME_INDEX_NumpadParenRight:
1323 case CODE_NAME_INDEX_NumpadSubtract:
1324 return eKeyLocationNumpad;
1325 default:
1326 return eKeyLocationStandard;
1330 /* static */
1331 uint32_t WidgetKeyboardEvent::ComputeKeyCodeFromKeyNameIndex(
1332 KeyNameIndex aKeyNameIndex) {
1333 switch (aKeyNameIndex) {
1334 case KEY_NAME_INDEX_Cancel:
1335 return dom::KeyboardEvent_Binding::DOM_VK_CANCEL;
1336 case KEY_NAME_INDEX_Help:
1337 return dom::KeyboardEvent_Binding::DOM_VK_HELP;
1338 case KEY_NAME_INDEX_Backspace:
1339 return dom::KeyboardEvent_Binding::DOM_VK_BACK_SPACE;
1340 case KEY_NAME_INDEX_Tab:
1341 return dom::KeyboardEvent_Binding::DOM_VK_TAB;
1342 case KEY_NAME_INDEX_Clear:
1343 return dom::KeyboardEvent_Binding::DOM_VK_CLEAR;
1344 case KEY_NAME_INDEX_Enter:
1345 return dom::KeyboardEvent_Binding::DOM_VK_RETURN;
1346 case KEY_NAME_INDEX_Shift:
1347 return dom::KeyboardEvent_Binding::DOM_VK_SHIFT;
1348 case KEY_NAME_INDEX_Control:
1349 return dom::KeyboardEvent_Binding::DOM_VK_CONTROL;
1350 case KEY_NAME_INDEX_Alt:
1351 return dom::KeyboardEvent_Binding::DOM_VK_ALT;
1352 case KEY_NAME_INDEX_Pause:
1353 return dom::KeyboardEvent_Binding::DOM_VK_PAUSE;
1354 case KEY_NAME_INDEX_CapsLock:
1355 return dom::KeyboardEvent_Binding::DOM_VK_CAPS_LOCK;
1356 case KEY_NAME_INDEX_Hiragana:
1357 case KEY_NAME_INDEX_Katakana:
1358 case KEY_NAME_INDEX_HiraganaKatakana:
1359 case KEY_NAME_INDEX_KanaMode:
1360 return dom::KeyboardEvent_Binding::DOM_VK_KANA;
1361 case KEY_NAME_INDEX_HangulMode:
1362 return dom::KeyboardEvent_Binding::DOM_VK_HANGUL;
1363 case KEY_NAME_INDEX_Eisu:
1364 return dom::KeyboardEvent_Binding::DOM_VK_EISU;
1365 case KEY_NAME_INDEX_JunjaMode:
1366 return dom::KeyboardEvent_Binding::DOM_VK_JUNJA;
1367 case KEY_NAME_INDEX_FinalMode:
1368 return dom::KeyboardEvent_Binding::DOM_VK_FINAL;
1369 case KEY_NAME_INDEX_HanjaMode:
1370 return dom::KeyboardEvent_Binding::DOM_VK_HANJA;
1371 case KEY_NAME_INDEX_KanjiMode:
1372 return dom::KeyboardEvent_Binding::DOM_VK_KANJI;
1373 case KEY_NAME_INDEX_Escape:
1374 return dom::KeyboardEvent_Binding::DOM_VK_ESCAPE;
1375 case KEY_NAME_INDEX_Convert:
1376 return dom::KeyboardEvent_Binding::DOM_VK_CONVERT;
1377 case KEY_NAME_INDEX_NonConvert:
1378 return dom::KeyboardEvent_Binding::DOM_VK_NONCONVERT;
1379 case KEY_NAME_INDEX_Accept:
1380 return dom::KeyboardEvent_Binding::DOM_VK_ACCEPT;
1381 case KEY_NAME_INDEX_ModeChange:
1382 return dom::KeyboardEvent_Binding::DOM_VK_MODECHANGE;
1383 case KEY_NAME_INDEX_PageUp:
1384 return dom::KeyboardEvent_Binding::DOM_VK_PAGE_UP;
1385 case KEY_NAME_INDEX_PageDown:
1386 return dom::KeyboardEvent_Binding::DOM_VK_PAGE_DOWN;
1387 case KEY_NAME_INDEX_End:
1388 return dom::KeyboardEvent_Binding::DOM_VK_END;
1389 case KEY_NAME_INDEX_Home:
1390 return dom::KeyboardEvent_Binding::DOM_VK_HOME;
1391 case KEY_NAME_INDEX_ArrowLeft:
1392 return dom::KeyboardEvent_Binding::DOM_VK_LEFT;
1393 case KEY_NAME_INDEX_ArrowUp:
1394 return dom::KeyboardEvent_Binding::DOM_VK_UP;
1395 case KEY_NAME_INDEX_ArrowRight:
1396 return dom::KeyboardEvent_Binding::DOM_VK_RIGHT;
1397 case KEY_NAME_INDEX_ArrowDown:
1398 return dom::KeyboardEvent_Binding::DOM_VK_DOWN;
1399 case KEY_NAME_INDEX_Select:
1400 return dom::KeyboardEvent_Binding::DOM_VK_SELECT;
1401 case KEY_NAME_INDEX_Print:
1402 return dom::KeyboardEvent_Binding::DOM_VK_PRINT;
1403 case KEY_NAME_INDEX_Execute:
1404 return dom::KeyboardEvent_Binding::DOM_VK_EXECUTE;
1405 case KEY_NAME_INDEX_PrintScreen:
1406 return dom::KeyboardEvent_Binding::DOM_VK_PRINTSCREEN;
1407 case KEY_NAME_INDEX_Insert:
1408 return dom::KeyboardEvent_Binding::DOM_VK_INSERT;
1409 case KEY_NAME_INDEX_Delete:
1410 return dom::KeyboardEvent_Binding::DOM_VK_DELETE;
1411 case KEY_NAME_INDEX_OS:
1412 // case KEY_NAME_INDEX_Super:
1413 // case KEY_NAME_INDEX_Hyper:
1414 return dom::KeyboardEvent_Binding::DOM_VK_WIN;
1415 case KEY_NAME_INDEX_ContextMenu:
1416 return dom::KeyboardEvent_Binding::DOM_VK_CONTEXT_MENU;
1417 case KEY_NAME_INDEX_Standby:
1418 return dom::KeyboardEvent_Binding::DOM_VK_SLEEP;
1419 case KEY_NAME_INDEX_F1:
1420 return dom::KeyboardEvent_Binding::DOM_VK_F1;
1421 case KEY_NAME_INDEX_F2:
1422 return dom::KeyboardEvent_Binding::DOM_VK_F2;
1423 case KEY_NAME_INDEX_F3:
1424 return dom::KeyboardEvent_Binding::DOM_VK_F3;
1425 case KEY_NAME_INDEX_F4:
1426 return dom::KeyboardEvent_Binding::DOM_VK_F4;
1427 case KEY_NAME_INDEX_F5:
1428 return dom::KeyboardEvent_Binding::DOM_VK_F5;
1429 case KEY_NAME_INDEX_F6:
1430 return dom::KeyboardEvent_Binding::DOM_VK_F6;
1431 case KEY_NAME_INDEX_F7:
1432 return dom::KeyboardEvent_Binding::DOM_VK_F7;
1433 case KEY_NAME_INDEX_F8:
1434 return dom::KeyboardEvent_Binding::DOM_VK_F8;
1435 case KEY_NAME_INDEX_F9:
1436 return dom::KeyboardEvent_Binding::DOM_VK_F9;
1437 case KEY_NAME_INDEX_F10:
1438 return dom::KeyboardEvent_Binding::DOM_VK_F10;
1439 case KEY_NAME_INDEX_F11:
1440 return dom::KeyboardEvent_Binding::DOM_VK_F11;
1441 case KEY_NAME_INDEX_F12:
1442 return dom::KeyboardEvent_Binding::DOM_VK_F12;
1443 case KEY_NAME_INDEX_F13:
1444 return dom::KeyboardEvent_Binding::DOM_VK_F13;
1445 case KEY_NAME_INDEX_F14:
1446 return dom::KeyboardEvent_Binding::DOM_VK_F14;
1447 case KEY_NAME_INDEX_F15:
1448 return dom::KeyboardEvent_Binding::DOM_VK_F15;
1449 case KEY_NAME_INDEX_F16:
1450 return dom::KeyboardEvent_Binding::DOM_VK_F16;
1451 case KEY_NAME_INDEX_F17:
1452 return dom::KeyboardEvent_Binding::DOM_VK_F17;
1453 case KEY_NAME_INDEX_F18:
1454 return dom::KeyboardEvent_Binding::DOM_VK_F18;
1455 case KEY_NAME_INDEX_F19:
1456 return dom::KeyboardEvent_Binding::DOM_VK_F19;
1457 case KEY_NAME_INDEX_F20:
1458 return dom::KeyboardEvent_Binding::DOM_VK_F20;
1459 case KEY_NAME_INDEX_F21:
1460 return dom::KeyboardEvent_Binding::DOM_VK_F21;
1461 case KEY_NAME_INDEX_F22:
1462 return dom::KeyboardEvent_Binding::DOM_VK_F22;
1463 case KEY_NAME_INDEX_F23:
1464 return dom::KeyboardEvent_Binding::DOM_VK_F23;
1465 case KEY_NAME_INDEX_F24:
1466 return dom::KeyboardEvent_Binding::DOM_VK_F24;
1467 case KEY_NAME_INDEX_NumLock:
1468 return dom::KeyboardEvent_Binding::DOM_VK_NUM_LOCK;
1469 case KEY_NAME_INDEX_ScrollLock:
1470 return dom::KeyboardEvent_Binding::DOM_VK_SCROLL_LOCK;
1471 case KEY_NAME_INDEX_AudioVolumeMute:
1472 return dom::KeyboardEvent_Binding::DOM_VK_VOLUME_MUTE;
1473 case KEY_NAME_INDEX_AudioVolumeDown:
1474 return dom::KeyboardEvent_Binding::DOM_VK_VOLUME_DOWN;
1475 case KEY_NAME_INDEX_AudioVolumeUp:
1476 return dom::KeyboardEvent_Binding::DOM_VK_VOLUME_UP;
1477 case KEY_NAME_INDEX_Meta:
1478 return dom::KeyboardEvent_Binding::DOM_VK_META;
1479 case KEY_NAME_INDEX_AltGraph:
1480 return dom::KeyboardEvent_Binding::DOM_VK_ALTGR;
1481 case KEY_NAME_INDEX_Process:
1482 return dom::KeyboardEvent_Binding::DOM_VK_PROCESSKEY;
1483 case KEY_NAME_INDEX_Attn:
1484 return dom::KeyboardEvent_Binding::DOM_VK_ATTN;
1485 case KEY_NAME_INDEX_CrSel:
1486 return dom::KeyboardEvent_Binding::DOM_VK_CRSEL;
1487 case KEY_NAME_INDEX_ExSel:
1488 return dom::KeyboardEvent_Binding::DOM_VK_EXSEL;
1489 case KEY_NAME_INDEX_EraseEof:
1490 return dom::KeyboardEvent_Binding::DOM_VK_EREOF;
1491 case KEY_NAME_INDEX_Play:
1492 return dom::KeyboardEvent_Binding::DOM_VK_PLAY;
1493 case KEY_NAME_INDEX_ZoomToggle:
1494 case KEY_NAME_INDEX_ZoomIn:
1495 case KEY_NAME_INDEX_ZoomOut:
1496 return dom::KeyboardEvent_Binding::DOM_VK_ZOOM;
1497 default:
1498 return 0;
1502 /* static */
1503 CodeNameIndex WidgetKeyboardEvent::ComputeCodeNameIndexFromKeyNameIndex(
1504 KeyNameIndex aKeyNameIndex, const Maybe<uint32_t>& aLocation) {
1505 if (aLocation.isSome() &&
1506 aLocation.value() ==
1507 dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_NUMPAD) {
1508 // On macOS, NumLock is not supported. Therefore, this handles
1509 // control key values except "Enter" only on non-macOS platforms.
1510 switch (aKeyNameIndex) {
1511 #ifndef XP_MACOSX
1512 case KEY_NAME_INDEX_Insert:
1513 return CODE_NAME_INDEX_Numpad0;
1514 case KEY_NAME_INDEX_End:
1515 return CODE_NAME_INDEX_Numpad1;
1516 case KEY_NAME_INDEX_ArrowDown:
1517 return CODE_NAME_INDEX_Numpad2;
1518 case KEY_NAME_INDEX_PageDown:
1519 return CODE_NAME_INDEX_Numpad3;
1520 case KEY_NAME_INDEX_ArrowLeft:
1521 return CODE_NAME_INDEX_Numpad4;
1522 case KEY_NAME_INDEX_Clear:
1523 // FYI: "Clear" on macOS should be DOM_KEY_LOCATION_STANDARD.
1524 return CODE_NAME_INDEX_Numpad5;
1525 case KEY_NAME_INDEX_ArrowRight:
1526 return CODE_NAME_INDEX_Numpad6;
1527 case KEY_NAME_INDEX_Home:
1528 return CODE_NAME_INDEX_Numpad7;
1529 case KEY_NAME_INDEX_ArrowUp:
1530 return CODE_NAME_INDEX_Numpad8;
1531 case KEY_NAME_INDEX_PageUp:
1532 return CODE_NAME_INDEX_Numpad9;
1533 case KEY_NAME_INDEX_Delete:
1534 return CODE_NAME_INDEX_NumpadDecimal;
1535 #endif // #ifndef XP_MACOSX
1536 case KEY_NAME_INDEX_Enter:
1537 return CODE_NAME_INDEX_NumpadEnter;
1538 default:
1539 return CODE_NAME_INDEX_UNKNOWN;
1543 if (WidgetKeyboardEvent::IsLeftOrRightModiferKeyNameIndex(aKeyNameIndex)) {
1544 if (aLocation.isSome() &&
1545 (aLocation.value() !=
1546 dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_LEFT &&
1547 aLocation.value() !=
1548 dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_RIGHT)) {
1549 return CODE_NAME_INDEX_UNKNOWN;
1551 bool isRight =
1552 aLocation.isSome() &&
1553 aLocation.value() == dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_RIGHT;
1554 switch (aKeyNameIndex) {
1555 case KEY_NAME_INDEX_Alt:
1556 return isRight ? CODE_NAME_INDEX_AltRight : CODE_NAME_INDEX_AltLeft;
1557 case KEY_NAME_INDEX_Control:
1558 return isRight ? CODE_NAME_INDEX_ControlRight
1559 : CODE_NAME_INDEX_ControlLeft;
1560 case KEY_NAME_INDEX_Shift:
1561 return isRight ? CODE_NAME_INDEX_ShiftRight : CODE_NAME_INDEX_ShiftLeft;
1562 #if defined(XP_WIN)
1563 case KEY_NAME_INDEX_Meta:
1564 return CODE_NAME_INDEX_UNKNOWN;
1565 case KEY_NAME_INDEX_OS: // win key.
1566 return isRight ? CODE_NAME_INDEX_OSRight : CODE_NAME_INDEX_OSLeft;
1567 #elif defined(XP_MACOSX) || defined(ANDROID)
1568 case KEY_NAME_INDEX_Meta: // command key.
1569 return isRight ? CODE_NAME_INDEX_OSRight : CODE_NAME_INDEX_OSLeft;
1570 case KEY_NAME_INDEX_OS:
1571 return CODE_NAME_INDEX_UNKNOWN;
1572 #else
1573 case KEY_NAME_INDEX_Meta: // Alt + Shift.
1574 return isRight ? CODE_NAME_INDEX_AltRight : CODE_NAME_INDEX_AltLeft;
1575 case KEY_NAME_INDEX_OS: // Super/Hyper key.
1576 return isRight ? CODE_NAME_INDEX_OSRight : CODE_NAME_INDEX_OSLeft;
1577 #endif
1578 default:
1579 return CODE_NAME_INDEX_UNKNOWN;
1583 if (aLocation.isSome() &&
1584 aLocation.value() !=
1585 dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_STANDARD) {
1586 return CODE_NAME_INDEX_UNKNOWN;
1589 switch (aKeyNameIndex) {
1590 // Standard section:
1591 case KEY_NAME_INDEX_Escape:
1592 return CODE_NAME_INDEX_Escape;
1593 case KEY_NAME_INDEX_Tab:
1594 return CODE_NAME_INDEX_Tab;
1595 case KEY_NAME_INDEX_CapsLock:
1596 return CODE_NAME_INDEX_CapsLock;
1597 case KEY_NAME_INDEX_ContextMenu:
1598 return CODE_NAME_INDEX_ContextMenu;
1599 case KEY_NAME_INDEX_Backspace:
1600 return CODE_NAME_INDEX_Backspace;
1601 case KEY_NAME_INDEX_Enter:
1602 return CODE_NAME_INDEX_Enter;
1603 #ifdef XP_MACOSX
1604 // Although, macOS does not fire native key event of "Fn" key, we support
1605 // Fn key event if it's sent by other apps directly.
1606 case KEY_NAME_INDEX_Fn:
1607 return CODE_NAME_INDEX_Fn;
1608 #endif // #ifdef
1610 // Arrow Pad section:
1611 case KEY_NAME_INDEX_ArrowLeft:
1612 return CODE_NAME_INDEX_ArrowLeft;
1613 case KEY_NAME_INDEX_ArrowUp:
1614 return CODE_NAME_INDEX_ArrowUp;
1615 case KEY_NAME_INDEX_ArrowDown:
1616 return CODE_NAME_INDEX_ArrowDown;
1617 case KEY_NAME_INDEX_ArrowRight:
1618 return CODE_NAME_INDEX_ArrowRight;
1620 // Control Pad section:
1621 #ifndef XP_MACOSX
1622 case KEY_NAME_INDEX_Insert:
1623 return CODE_NAME_INDEX_Insert;
1624 #else
1625 case KEY_NAME_INDEX_Help:
1626 return CODE_NAME_INDEX_Help;
1627 #endif // #ifndef XP_MACOSX #else
1628 case KEY_NAME_INDEX_Delete:
1629 return CODE_NAME_INDEX_Delete;
1630 case KEY_NAME_INDEX_Home:
1631 return CODE_NAME_INDEX_Home;
1632 case KEY_NAME_INDEX_End:
1633 return CODE_NAME_INDEX_End;
1634 case KEY_NAME_INDEX_PageUp:
1635 return CODE_NAME_INDEX_PageUp;
1636 case KEY_NAME_INDEX_PageDown:
1637 return CODE_NAME_INDEX_PageDown;
1639 // Function keys:
1640 case KEY_NAME_INDEX_F1:
1641 return CODE_NAME_INDEX_F1;
1642 case KEY_NAME_INDEX_F2:
1643 return CODE_NAME_INDEX_F2;
1644 case KEY_NAME_INDEX_F3:
1645 return CODE_NAME_INDEX_F3;
1646 case KEY_NAME_INDEX_F4:
1647 return CODE_NAME_INDEX_F4;
1648 case KEY_NAME_INDEX_F5:
1649 return CODE_NAME_INDEX_F5;
1650 case KEY_NAME_INDEX_F6:
1651 return CODE_NAME_INDEX_F6;
1652 case KEY_NAME_INDEX_F7:
1653 return CODE_NAME_INDEX_F7;
1654 case KEY_NAME_INDEX_F8:
1655 return CODE_NAME_INDEX_F8;
1656 case KEY_NAME_INDEX_F9:
1657 return CODE_NAME_INDEX_F9;
1658 case KEY_NAME_INDEX_F10:
1659 return CODE_NAME_INDEX_F10;
1660 case KEY_NAME_INDEX_F11:
1661 return CODE_NAME_INDEX_F11;
1662 case KEY_NAME_INDEX_F12:
1663 return CODE_NAME_INDEX_F12;
1664 case KEY_NAME_INDEX_F13:
1665 return CODE_NAME_INDEX_F13;
1666 case KEY_NAME_INDEX_F14:
1667 return CODE_NAME_INDEX_F14;
1668 case KEY_NAME_INDEX_F15:
1669 return CODE_NAME_INDEX_F15;
1670 case KEY_NAME_INDEX_F16:
1671 return CODE_NAME_INDEX_F16;
1672 case KEY_NAME_INDEX_F17:
1673 return CODE_NAME_INDEX_F17;
1674 case KEY_NAME_INDEX_F18:
1675 return CODE_NAME_INDEX_F18;
1676 case KEY_NAME_INDEX_F19:
1677 return CODE_NAME_INDEX_F19;
1678 case KEY_NAME_INDEX_F20:
1679 return CODE_NAME_INDEX_F20;
1680 #ifndef XP_MACOSX
1681 case KEY_NAME_INDEX_F21:
1682 return CODE_NAME_INDEX_F21;
1683 case KEY_NAME_INDEX_F22:
1684 return CODE_NAME_INDEX_F22;
1685 case KEY_NAME_INDEX_F23:
1686 return CODE_NAME_INDEX_F23;
1687 case KEY_NAME_INDEX_F24:
1688 return CODE_NAME_INDEX_F24;
1689 case KEY_NAME_INDEX_Pause:
1690 return CODE_NAME_INDEX_Pause;
1691 case KEY_NAME_INDEX_PrintScreen:
1692 return CODE_NAME_INDEX_PrintScreen;
1693 case KEY_NAME_INDEX_ScrollLock:
1694 return CODE_NAME_INDEX_ScrollLock;
1695 #endif // #ifndef XP_MACOSX
1697 // NumLock key:
1698 #ifndef XP_MACOSX
1699 case KEY_NAME_INDEX_NumLock:
1700 return CODE_NAME_INDEX_NumLock;
1701 #else
1702 case KEY_NAME_INDEX_Clear:
1703 return CODE_NAME_INDEX_NumLock;
1704 #endif // #ifndef XP_MACOSX #else
1706 // Media keys:
1707 case KEY_NAME_INDEX_AudioVolumeDown:
1708 return CODE_NAME_INDEX_VolumeDown;
1709 case KEY_NAME_INDEX_AudioVolumeMute:
1710 return CODE_NAME_INDEX_VolumeMute;
1711 case KEY_NAME_INDEX_AudioVolumeUp:
1712 return CODE_NAME_INDEX_VolumeUp;
1713 #ifndef XP_MACOSX
1714 case KEY_NAME_INDEX_BrowserBack:
1715 return CODE_NAME_INDEX_BrowserBack;
1716 case KEY_NAME_INDEX_BrowserFavorites:
1717 return CODE_NAME_INDEX_BrowserFavorites;
1718 case KEY_NAME_INDEX_BrowserForward:
1719 return CODE_NAME_INDEX_BrowserForward;
1720 case KEY_NAME_INDEX_BrowserRefresh:
1721 return CODE_NAME_INDEX_BrowserRefresh;
1722 case KEY_NAME_INDEX_BrowserSearch:
1723 return CODE_NAME_INDEX_BrowserSearch;
1724 case KEY_NAME_INDEX_BrowserStop:
1725 return CODE_NAME_INDEX_BrowserStop;
1726 case KEY_NAME_INDEX_MediaPlayPause:
1727 return CODE_NAME_INDEX_MediaPlayPause;
1728 case KEY_NAME_INDEX_MediaStop:
1729 return CODE_NAME_INDEX_MediaStop;
1730 case KEY_NAME_INDEX_MediaTrackNext:
1731 return CODE_NAME_INDEX_MediaTrackNext;
1732 case KEY_NAME_INDEX_MediaTrackPrevious:
1733 return CODE_NAME_INDEX_MediaTrackPrevious;
1734 case KEY_NAME_INDEX_LaunchApplication1:
1735 return CODE_NAME_INDEX_LaunchApp1;
1736 #endif // #ifndef XP_MACOSX
1738 // Only Windows and GTK supports the following multimedia keys.
1739 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
1740 case KEY_NAME_INDEX_BrowserHome:
1741 return CODE_NAME_INDEX_BrowserHome;
1742 case KEY_NAME_INDEX_LaunchApplication2:
1743 return CODE_NAME_INDEX_LaunchApp2;
1744 #endif // #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
1746 // Only GTK and Android supports the following multimedia keys.
1747 #if defined(MOZ_WIDGET_GTK) || defined(ANDROID)
1748 case KEY_NAME_INDEX_Eject:
1749 return CODE_NAME_INDEX_Eject;
1750 case KEY_NAME_INDEX_WakeUp:
1751 return CODE_NAME_INDEX_WakeUp;
1752 #endif // #if defined(MOZ_WIDGET_GTK) || defined(ANDROID)
1754 // Only Windows does not support Help key (and macOS handled above).
1755 #if !defined(XP_WIN) && !defined(XP_MACOSX)
1756 case KEY_NAME_INDEX_Help:
1757 return CODE_NAME_INDEX_Help;
1758 #endif // #if !defined(XP_WIN) && !defined(XP_MACOSX)
1760 // IME specific keys:
1761 #ifdef XP_WIN
1762 case KEY_NAME_INDEX_Convert:
1763 return CODE_NAME_INDEX_Convert;
1764 case KEY_NAME_INDEX_NonConvert:
1765 return CODE_NAME_INDEX_NonConvert;
1766 case KEY_NAME_INDEX_Alphanumeric:
1767 return CODE_NAME_INDEX_CapsLock;
1768 case KEY_NAME_INDEX_KanaMode:
1769 case KEY_NAME_INDEX_Romaji:
1770 case KEY_NAME_INDEX_Katakana:
1771 case KEY_NAME_INDEX_Hiragana:
1772 return CODE_NAME_INDEX_KanaMode;
1773 case KEY_NAME_INDEX_Hankaku:
1774 case KEY_NAME_INDEX_Zenkaku:
1775 case KEY_NAME_INDEX_KanjiMode:
1776 return CODE_NAME_INDEX_Backquote;
1777 case KEY_NAME_INDEX_HanjaMode:
1778 return CODE_NAME_INDEX_Lang2;
1779 case KEY_NAME_INDEX_HangulMode:
1780 return CODE_NAME_INDEX_Lang1;
1781 #endif // #ifdef XP_WIN
1783 #ifdef MOZ_WIDGET_GTK
1784 case KEY_NAME_INDEX_Convert:
1785 return CODE_NAME_INDEX_Convert;
1786 case KEY_NAME_INDEX_NonConvert:
1787 return CODE_NAME_INDEX_NonConvert;
1788 case KEY_NAME_INDEX_Alphanumeric:
1789 return CODE_NAME_INDEX_CapsLock;
1790 case KEY_NAME_INDEX_HiraganaKatakana:
1791 return CODE_NAME_INDEX_KanaMode;
1792 case KEY_NAME_INDEX_ZenkakuHankaku:
1793 return CODE_NAME_INDEX_Backquote;
1794 #endif // #ifdef MOZ_WIDGET_GTK
1796 #ifdef ANDROID
1797 case KEY_NAME_INDEX_Convert:
1798 return CODE_NAME_INDEX_Convert;
1799 case KEY_NAME_INDEX_NonConvert:
1800 return CODE_NAME_INDEX_NonConvert;
1801 case KEY_NAME_INDEX_HiraganaKatakana:
1802 return CODE_NAME_INDEX_KanaMode;
1803 case KEY_NAME_INDEX_ZenkakuHankaku:
1804 return CODE_NAME_INDEX_Backquote;
1805 case KEY_NAME_INDEX_Eisu:
1806 return CODE_NAME_INDEX_Lang2;
1807 case KEY_NAME_INDEX_KanjiMode:
1808 return CODE_NAME_INDEX_Lang1;
1809 #endif // #ifdef ANDROID
1811 #ifdef XP_MACOSX
1812 case KEY_NAME_INDEX_Eisu:
1813 return CODE_NAME_INDEX_Lang2;
1814 case KEY_NAME_INDEX_KanjiMode:
1815 return CODE_NAME_INDEX_Lang1;
1816 #endif // #ifdef XP_MACOSX
1818 default:
1819 return CODE_NAME_INDEX_UNKNOWN;
1823 /* static */
1824 Modifier WidgetKeyboardEvent::GetModifierForKeyName(
1825 KeyNameIndex aKeyNameIndex) {
1826 switch (aKeyNameIndex) {
1827 case KEY_NAME_INDEX_Alt:
1828 return MODIFIER_ALT;
1829 case KEY_NAME_INDEX_AltGraph:
1830 return MODIFIER_ALTGRAPH;
1831 case KEY_NAME_INDEX_CapsLock:
1832 return MODIFIER_CAPSLOCK;
1833 case KEY_NAME_INDEX_Control:
1834 return MODIFIER_CONTROL;
1835 case KEY_NAME_INDEX_Fn:
1836 return MODIFIER_FN;
1837 case KEY_NAME_INDEX_FnLock:
1838 return MODIFIER_FNLOCK;
1839 // case KEY_NAME_INDEX_Hyper:
1840 case KEY_NAME_INDEX_Meta:
1841 return MODIFIER_META;
1842 case KEY_NAME_INDEX_NumLock:
1843 return MODIFIER_NUMLOCK;
1844 case KEY_NAME_INDEX_OS:
1845 return MODIFIER_OS;
1846 case KEY_NAME_INDEX_ScrollLock:
1847 return MODIFIER_SCROLLLOCK;
1848 case KEY_NAME_INDEX_Shift:
1849 return MODIFIER_SHIFT;
1850 // case KEY_NAME_INDEX_Super:
1851 case KEY_NAME_INDEX_Symbol:
1852 return MODIFIER_SYMBOL;
1853 case KEY_NAME_INDEX_SymbolLock:
1854 return MODIFIER_SYMBOLLOCK;
1855 default:
1856 return MODIFIER_NONE;
1860 /* static */
1861 bool WidgetKeyboardEvent::IsLockableModifier(KeyNameIndex aKeyNameIndex) {
1862 switch (aKeyNameIndex) {
1863 case KEY_NAME_INDEX_CapsLock:
1864 case KEY_NAME_INDEX_FnLock:
1865 case KEY_NAME_INDEX_NumLock:
1866 case KEY_NAME_INDEX_ScrollLock:
1867 case KEY_NAME_INDEX_SymbolLock:
1868 return true;
1869 default:
1870 return false;
1874 /******************************************************************************
1875 * mozilla::InternalEditorInputEvent (TextEvents.h)
1876 ******************************************************************************/
1878 #define NS_DEFINE_INPUTTYPE(aCPPName, aDOMName) (u"" aDOMName),
1879 const char16_t* const InternalEditorInputEvent::kInputTypeNames[] = {
1880 #include "mozilla/InputTypeList.h"
1882 #undef NS_DEFINE_INPUTTYPE
1884 InternalEditorInputEvent::InputTypeHashtable*
1885 InternalEditorInputEvent::sInputTypeHashtable = nullptr;
1887 /* static */
1888 void InternalEditorInputEvent::Shutdown() {
1889 delete sInputTypeHashtable;
1890 sInputTypeHashtable = nullptr;
1893 /* static */
1894 void InternalEditorInputEvent::GetDOMInputTypeName(EditorInputType aInputType,
1895 nsAString& aInputTypeName) {
1896 if (static_cast<size_t>(aInputType) >=
1897 static_cast<size_t>(EditorInputType::eUnknown)) {
1898 aInputTypeName.Truncate();
1899 return;
1902 MOZ_RELEASE_ASSERT(
1903 static_cast<size_t>(aInputType) < ArrayLength(kInputTypeNames),
1904 "Illegal input type enumeration value");
1905 aInputTypeName.Assign(kInputTypeNames[static_cast<size_t>(aInputType)]);
1908 /* static */
1909 EditorInputType InternalEditorInputEvent::GetEditorInputType(
1910 const nsAString& aInputType) {
1911 if (aInputType.IsEmpty()) {
1912 return EditorInputType::eUnknown;
1915 if (!sInputTypeHashtable) {
1916 sInputTypeHashtable = new InputTypeHashtable(ArrayLength(kInputTypeNames));
1917 for (size_t i = 0; i < ArrayLength(kInputTypeNames); i++) {
1918 sInputTypeHashtable->InsertOrUpdate(nsDependentString(kInputTypeNames[i]),
1919 static_cast<EditorInputType>(i));
1922 return sInputTypeHashtable->MaybeGet(aInputType)
1923 .valueOr(EditorInputType::eUnknown);
1926 } // namespace mozilla