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