Bug 1905865 - [devtools] Update webidl-pure-allowlist.js. r=devtools-reviewers,ochameau.
[gecko.git] / widget / WidgetEventImpl.cpp
blobbcf8a7b597c8ffc5d6e58b4752e5f522030ad178
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 "BasicEvents.h"
7 #include "ContentEvents.h"
8 #include "MiscEvents.h"
9 #include "MouseEvents.h"
10 #include "NativeKeyBindingsType.h"
11 #include "TextEventDispatcher.h"
12 #include "TextEvents.h"
13 #include "TouchEvents.h"
15 #include "mozilla/EventStateManager.h"
16 #include "mozilla/InternalMutationEvent.h"
17 #include "mozilla/Maybe.h"
18 #include "mozilla/Preferences.h"
19 #include "mozilla/StaticPrefs_dom.h"
20 #include "mozilla/StaticPrefs_mousewheel.h"
21 #include "mozilla/StaticPrefs_ui.h"
22 #include "mozilla/WritingModes.h"
23 #include "mozilla/dom/KeyboardEventBinding.h"
24 #include "mozilla/dom/MouseEventBinding.h"
25 #include "mozilla/dom/WheelEventBinding.h"
26 #include "nsCommandParams.h"
27 #include "nsContentUtils.h"
28 #include "nsIContent.h"
29 #include "nsIDragSession.h"
30 #include "nsPrintfCString.h"
32 #if defined(XP_WIN)
33 # include "windef.h"
34 # include "winnetwk.h"
35 # include "npapi.h"
36 # include "WinUtils.h"
37 #endif // #if defined (XP_WIN)
39 #if defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
40 # include "NativeKeyBindings.h"
41 #endif // #if defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
43 namespace mozilla {
45 /******************************************************************************
46 * Global helper methods
47 ******************************************************************************/
49 const char* ToChar(EventMessage aEventMessage) {
50 switch (aEventMessage) {
51 #define NS_EVENT_MESSAGE(aMessage) \
52 case aMessage: \
53 return #aMessage;
55 #include "mozilla/EventMessageList.h"
57 #undef NS_EVENT_MESSAGE
58 default:
59 return "illegal event message";
63 bool IsPointerEventMessage(EventMessage aMessage) {
64 switch (aMessage) {
65 case ePointerDown:
66 case ePointerMove:
67 case ePointerUp:
68 case ePointerCancel:
69 case ePointerOver:
70 case ePointerOut:
71 case ePointerEnter:
72 case ePointerLeave:
73 case ePointerGotCapture:
74 case ePointerLostCapture:
75 return true;
76 case ePointerClick:
77 case ePointerAuxClick:
78 case eContextMenu:
79 return StaticPrefs::
80 dom_w3c_pointer_events_dispatch_click_as_pointer_event();
81 default:
82 return false;
86 bool IsPointerEventMessageOriginallyMouseEventMessage(EventMessage aMessage) {
87 return StaticPrefs::
88 dom_w3c_pointer_events_dispatch_click_as_pointer_event() &&
89 (aMessage == ePointerClick || aMessage == ePointerAuxClick ||
90 aMessage == eContextMenu);
93 const char* ToChar(EventClassID aEventClassID) {
94 switch (aEventClassID) {
95 #define NS_ROOT_EVENT_CLASS(aPrefix, aName) \
96 case eBasic##aName##Class: \
97 return "eBasic" #aName "Class";
99 #define NS_EVENT_CLASS(aPrefix, aName) \
100 case e##aName##Class: \
101 return "e" #aName "Class";
103 #include "mozilla/EventClassList.h"
105 #undef NS_EVENT_CLASS
106 #undef NS_ROOT_EVENT_CLASS
107 default:
108 return "illegal event class ID";
112 const nsCString ToString(KeyNameIndex aKeyNameIndex) {
113 if (aKeyNameIndex == KEY_NAME_INDEX_USE_STRING) {
114 return "USE_STRING"_ns;
116 nsAutoString keyName;
117 WidgetKeyboardEvent::GetDOMKeyName(aKeyNameIndex, keyName);
118 return NS_ConvertUTF16toUTF8(keyName);
121 const nsCString ToString(CodeNameIndex aCodeNameIndex) {
122 if (aCodeNameIndex == CODE_NAME_INDEX_USE_STRING) {
123 return "USE_STRING"_ns;
125 nsAutoString codeName;
126 WidgetKeyboardEvent::GetDOMCodeName(aCodeNameIndex, codeName);
127 return NS_ConvertUTF16toUTF8(codeName);
130 const char* ToChar(Command aCommand) {
131 if (aCommand == Command::DoNothing) {
132 return "CommandDoNothing";
135 switch (aCommand) {
136 #define NS_DEFINE_COMMAND(aName, aCommandStr) \
137 case Command::aName: \
138 return "Command::" #aName;
139 #define NS_DEFINE_COMMAND_WITH_PARAM(aName, aCommandStr, aParam) \
140 case Command::aName: \
141 return "Command::" #aName;
142 #define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName) \
143 case Command::aName: \
144 return "Command::" #aName;
146 #include "mozilla/CommandList.h"
148 #undef NS_DEFINE_COMMAND
149 #undef NS_DEFINE_COMMAND_WITH_PARAM
150 #undef NS_DEFINE_COMMAND_NO_EXEC_COMMAND
152 default:
153 return "illegal command value";
157 const nsCString GetDOMKeyCodeName(uint32_t aKeyCode) {
158 switch (aKeyCode) {
159 #define NS_DISALLOW_SAME_KEYCODE
160 #define NS_DEFINE_VK(aDOMKeyName, aDOMKeyCode) \
161 case aDOMKeyCode: \
162 return nsLiteralCString(#aDOMKeyName);
164 #include "mozilla/VirtualKeyCodeList.h"
166 #undef NS_DEFINE_VK
167 #undef NS_DISALLOW_SAME_KEYCODE
169 default:
170 return nsPrintfCString("Invalid DOM keyCode (0x%08X)", aKeyCode);
174 bool IsValidRawTextRangeValue(RawTextRangeType aRawTextRangeType) {
175 switch (static_cast<TextRangeType>(aRawTextRangeType)) {
176 case TextRangeType::eUninitialized:
177 case TextRangeType::eCaret:
178 case TextRangeType::eRawClause:
179 case TextRangeType::eSelectedRawClause:
180 case TextRangeType::eConvertedClause:
181 case TextRangeType::eSelectedClause:
182 return true;
183 default:
184 return false;
188 RawTextRangeType ToRawTextRangeType(TextRangeType aTextRangeType) {
189 return static_cast<RawTextRangeType>(aTextRangeType);
192 TextRangeType ToTextRangeType(RawTextRangeType aRawTextRangeType) {
193 MOZ_ASSERT(IsValidRawTextRangeValue(aRawTextRangeType));
194 return static_cast<TextRangeType>(aRawTextRangeType);
197 const char* ToChar(TextRangeType aTextRangeType) {
198 switch (aTextRangeType) {
199 case TextRangeType::eUninitialized:
200 return "TextRangeType::eUninitialized";
201 case TextRangeType::eCaret:
202 return "TextRangeType::eCaret";
203 case TextRangeType::eRawClause:
204 return "TextRangeType::eRawClause";
205 case TextRangeType::eSelectedRawClause:
206 return "TextRangeType::eSelectedRawClause";
207 case TextRangeType::eConvertedClause:
208 return "TextRangeType::eConvertedClause";
209 case TextRangeType::eSelectedClause:
210 return "TextRangeType::eSelectedClause";
211 default:
212 return "Invalid TextRangeType";
216 SelectionType ToSelectionType(TextRangeType aTextRangeType) {
217 switch (aTextRangeType) {
218 case TextRangeType::eRawClause:
219 return SelectionType::eIMERawClause;
220 case TextRangeType::eSelectedRawClause:
221 return SelectionType::eIMESelectedRawClause;
222 case TextRangeType::eConvertedClause:
223 return SelectionType::eIMEConvertedClause;
224 case TextRangeType::eSelectedClause:
225 return SelectionType::eIMESelectedClause;
226 default:
227 MOZ_CRASH("TextRangeType is invalid");
228 return SelectionType::eNormal;
232 /******************************************************************************
233 * non class method implementation
234 ******************************************************************************/
236 static nsTHashMap<nsDepCharHashKey, Command>* sCommandHashtable = nullptr;
238 Command GetInternalCommand(const char* aCommandName,
239 const nsCommandParams* aCommandParams) {
240 if (!aCommandName) {
241 return Command::DoNothing;
244 // Special cases for "cmd_align". It's mapped to multiple internal commands
245 // with additional param. Therefore, we cannot handle it with the hashtable.
246 if (!strcmp(aCommandName, "cmd_align")) {
247 if (!aCommandParams) {
248 // Note that if this is called by EditorCommand::IsCommandEnabled(),
249 // it cannot set aCommandParams. So, don't warn in this case even though
250 // this is illegal case for DoCommandParams().
251 return Command::FormatJustify;
253 nsAutoCString cValue;
254 nsresult rv = aCommandParams->GetCString("state_attribute", cValue);
255 if (NS_FAILED(rv)) {
256 nsString value; // Avoid copying the string buffer with using nsString.
257 rv = aCommandParams->GetString("state_attribute", value);
258 if (NS_FAILED(rv)) {
259 return Command::FormatJustifyNone;
261 CopyUTF16toUTF8(value, cValue);
263 if (cValue.LowerCaseEqualsASCII("left")) {
264 return Command::FormatJustifyLeft;
266 if (cValue.LowerCaseEqualsASCII("right")) {
267 return Command::FormatJustifyRight;
269 if (cValue.LowerCaseEqualsASCII("center")) {
270 return Command::FormatJustifyCenter;
272 if (cValue.LowerCaseEqualsASCII("justify")) {
273 return Command::FormatJustifyFull;
275 if (cValue.IsEmpty()) {
276 return Command::FormatJustifyNone;
278 return Command::DoNothing;
281 if (!sCommandHashtable) {
282 sCommandHashtable = new nsTHashMap<nsDepCharHashKey, Command>();
283 #define NS_DEFINE_COMMAND(aName, aCommandStr) \
284 sCommandHashtable->InsertOrUpdate(#aCommandStr, Command::aName);
286 #define NS_DEFINE_COMMAND_WITH_PARAM(aName, aCommandStr, aParam)
288 #define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName)
290 #include "mozilla/CommandList.h"
292 #undef NS_DEFINE_COMMAND
293 #undef NS_DEFINE_COMMAND_WITH_PARAM
294 #undef NS_DEFINE_COMMAND_NO_EXEC_COMMAND
296 Command command = Command::DoNothing;
297 if (!sCommandHashtable->Get(aCommandName, &command)) {
298 return Command::DoNothing;
300 return command;
303 /******************************************************************************
304 * As*Event() implementation
305 ******************************************************************************/
307 #define NS_ROOT_EVENT_CLASS(aPrefix, aName)
308 #define NS_EVENT_CLASS(aPrefix, aName) \
309 aPrefix##aName* WidgetEvent::As##aName() { return nullptr; } \
311 const aPrefix##aName* WidgetEvent::As##aName() const { \
312 return const_cast<WidgetEvent*>(this)->As##aName(); \
315 #include "mozilla/EventClassList.h"
317 #undef NS_EVENT_CLASS
318 #undef NS_ROOT_EVENT_CLASS
320 /******************************************************************************
321 * mozilla::WidgetEvent
323 * Event struct type checking methods.
324 ******************************************************************************/
326 bool WidgetEvent::IsQueryContentEvent() const {
327 return mClass == eQueryContentEventClass;
330 bool WidgetEvent::IsSelectionEvent() const {
331 return mClass == eSelectionEventClass;
334 bool WidgetEvent::IsContentCommandEvent() const {
335 return mClass == eContentCommandEventClass;
338 /******************************************************************************
339 * mozilla::WidgetEvent
341 * Event message checking methods.
342 ******************************************************************************/
344 bool WidgetEvent::HasMouseEventMessage() const {
345 switch (mMessage) {
346 case eMouseDown:
347 case eMouseUp:
348 case eMouseDoubleClick:
349 case eMouseEnterIntoWidget:
350 case eMouseExitFromWidget:
351 case eMouseActivate:
352 case eMouseOver:
353 case eMouseOut:
354 case eMouseHitTest:
355 case eMouseMove:
356 return true;
357 // TODO: Perhaps, we should rename this method.
358 case ePointerClick:
359 case ePointerAuxClick:
360 return true;
361 default:
362 return false;
366 bool WidgetEvent::IsMouseEventClassOrHasClickRelatedPointerEvent() const {
367 return mClass == eMouseEventClass ||
368 IsPointerEventMessageOriginallyMouseEventMessage(mMessage);
371 bool WidgetEvent::HasDragEventMessage() const {
372 switch (mMessage) {
373 case eDragEnter:
374 case eDragOver:
375 case eDragExit:
376 case eDrag:
377 case eDragEnd:
378 case eDragStart:
379 case eDrop:
380 case eDragLeave:
381 return true;
382 default:
383 return false;
387 /* static */
388 bool WidgetEvent::IsKeyEventMessage(EventMessage aMessage) {
389 switch (aMessage) {
390 case eKeyDown:
391 case eKeyPress:
392 case eKeyUp:
393 case eAccessKeyNotFound:
394 return true;
395 default:
396 return false;
400 bool WidgetEvent::HasIMEEventMessage() const {
401 switch (mMessage) {
402 case eCompositionStart:
403 case eCompositionEnd:
404 case eCompositionUpdate:
405 case eCompositionChange:
406 case eCompositionCommitAsIs:
407 case eCompositionCommit:
408 return true;
409 default:
410 return false;
414 /******************************************************************************
415 * mozilla::WidgetEvent
417 * Specific event checking methods.
418 ******************************************************************************/
420 bool WidgetEvent::CanBeSentToRemoteProcess() const {
421 // If this event is explicitly marked as shouldn't be sent to remote process,
422 // just return false.
423 if (IsCrossProcessForwardingStopped()) {
424 return false;
427 if (mClass == eKeyboardEventClass || mClass == eWheelEventClass) {
428 return true;
431 switch (mMessage) {
432 case eMouseDown:
433 case eMouseUp:
434 case eMouseMove:
435 case eMouseExploreByTouch:
436 case eContextMenu:
437 case eMouseEnterIntoWidget:
438 case eMouseExitFromWidget:
439 case eMouseTouchDrag:
440 case eTouchStart:
441 case eTouchMove:
442 case eTouchEnd:
443 case eTouchCancel:
444 case eDragOver:
445 case eDragExit:
446 case eDrop:
447 return true;
448 default:
449 return false;
453 bool WidgetEvent::WillBeSentToRemoteProcess() const {
454 // This event won't be posted to remote process if it's already explicitly
455 // stopped.
456 if (IsCrossProcessForwardingStopped()) {
457 return false;
460 // When mOriginalTarget is nullptr, this method shouldn't be used.
461 if (NS_WARN_IF(!mOriginalTarget)) {
462 return false;
465 return EventStateManager::IsTopLevelRemoteTarget(
466 nsIContent::FromEventTarget(mOriginalTarget));
469 bool WidgetEvent::IsIMERelatedEvent() const {
470 return HasIMEEventMessage() || IsQueryContentEvent() || IsSelectionEvent();
473 bool WidgetEvent::IsUsingCoordinates() const {
474 const WidgetMouseEvent* mouseEvent = AsMouseEvent();
475 if (mouseEvent) {
476 return !mouseEvent->IsContextMenuKeyEvent();
478 return !HasKeyEventMessage() && !IsIMERelatedEvent() &&
479 !IsContentCommandEvent();
482 bool WidgetEvent::IsTargetedAtFocusedWindow() const {
483 const WidgetMouseEvent* mouseEvent = AsMouseEvent();
484 if (mouseEvent) {
485 return mouseEvent->IsContextMenuKeyEvent();
487 return HasKeyEventMessage() || IsIMERelatedEvent() || IsContentCommandEvent();
490 bool WidgetEvent::IsTargetedAtFocusedContent() const {
491 const WidgetMouseEvent* mouseEvent = AsMouseEvent();
492 if (mouseEvent) {
493 return mouseEvent->IsContextMenuKeyEvent();
495 return HasKeyEventMessage() || IsIMERelatedEvent();
498 bool WidgetEvent::IsAllowedToDispatchDOMEvent() const {
499 switch (mClass) {
500 case eMouseEventClass:
501 if (mMessage == eMouseTouchDrag) {
502 return false;
504 [[fallthrough]];
505 case ePointerEventClass:
506 // We want synthesized mouse moves to cause mouseover and mouseout
507 // DOM events (EventStateManager::PreHandleEvent), but not mousemove
508 // DOM events.
509 // Synthesized button up events also do not cause DOM events because they
510 // do not have a reliable mRefPoint.
511 return AsMouseEvent()->mReason == WidgetMouseEvent::eReal;
513 case eWheelEventClass: {
514 // wheel event whose all delta values are zero by user pref applied, it
515 // shouldn't cause a DOM event.
516 const WidgetWheelEvent* wheelEvent = AsWheelEvent();
517 return wheelEvent->mDeltaX != 0.0 || wheelEvent->mDeltaY != 0.0 ||
518 wheelEvent->mDeltaZ != 0.0;
520 case eTouchEventClass:
521 return mMessage != eTouchPointerCancel;
522 // Following events are handled in EventStateManager, so, we don't need to
523 // dispatch DOM event for them into the DOM tree.
524 case eQueryContentEventClass:
525 case eSelectionEventClass:
526 case eContentCommandEventClass:
527 return false;
529 default:
530 return true;
534 bool WidgetEvent::IsAllowedToDispatchInSystemGroup() const {
535 // We don't expect to implement default behaviors with pointer events because
536 // if we do, prevent default on mouse events can't prevent default behaviors
537 // anymore.
538 return mClass != ePointerEventClass ||
539 IsPointerEventMessageOriginallyMouseEventMessage(mMessage);
542 bool WidgetEvent::IsBlockedForFingerprintingResistance() const {
543 switch (mClass) {
544 case eKeyboardEventClass: {
545 const WidgetKeyboardEvent* keyboardEvent = AsKeyboardEvent();
547 return (keyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_Alt ||
548 keyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_Shift ||
549 keyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_Control ||
550 keyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_AltGraph);
552 case ePointerEventClass: {
553 if (IsPointerEventMessageOriginallyMouseEventMessage(mMessage)) {
554 return false;
557 const WidgetPointerEvent* pointerEvent = AsPointerEvent();
559 // We suppress the pointer events if it is not primary for fingerprinting
560 // resistance. It is because of that we want to spoof any pointer event
561 // into a mouse pointer event and the mouse pointer event only has
562 // isPrimary as true.
563 return !pointerEvent->mIsPrimary;
565 default:
566 return false;
570 bool WidgetEvent::AllowFlushingPendingNotifications() const {
571 if (mClass != eQueryContentEventClass) {
572 return true;
574 // If the dispatcher does not want a flush of pending notifications, it may
575 // be caused by that it's unsafe. Therefore, we should allow handlers to
576 // flush pending things only when the dispatcher requires the latest content
577 // layout.
578 return AsQueryContentEvent()->mNeedsToFlushLayout;
581 /******************************************************************************
582 * mozilla::WidgetEvent
584 * Misc methods.
585 ******************************************************************************/
587 static dom::EventTarget* GetTargetForDOMEvent(dom::EventTarget* aTarget) {
588 return aTarget ? aTarget->GetTargetForDOMEvent() : nullptr;
591 dom::EventTarget* WidgetEvent::GetDOMEventTarget() const {
592 return GetTargetForDOMEvent(mTarget);
595 dom::EventTarget* WidgetEvent::GetCurrentDOMEventTarget() const {
596 return GetTargetForDOMEvent(mCurrentTarget);
599 dom::EventTarget* WidgetEvent::GetOriginalDOMEventTarget() const {
600 if (mOriginalTarget) {
601 return GetTargetForDOMEvent(mOriginalTarget);
603 return GetDOMEventTarget();
606 void WidgetEvent::PreventDefault(bool aCalledByDefaultHandler,
607 nsIPrincipal* aPrincipal) {
608 if (mMessage == ePointerDown) {
609 if (aCalledByDefaultHandler) {
610 // Shouldn't prevent default on pointerdown by default handlers to stop
611 // firing legacy mouse events. Use MOZ_ASSERT to catch incorrect usages
612 // in debug builds.
613 MOZ_ASSERT(false);
614 return;
616 if (aPrincipal) {
617 nsAutoString addonId;
618 Unused << NS_WARN_IF(NS_FAILED(aPrincipal->GetAddonId(addonId)));
619 if (!addonId.IsEmpty()) {
620 // Ignore the case that it's called by a web extension.
621 return;
625 mFlags.PreventDefault(aCalledByDefaultHandler);
628 bool WidgetEvent::IsUserAction() const {
629 if (!IsTrusted()) {
630 return false;
632 // FYI: eMouseScrollEventClass and ePointerEventClass represent
633 // user action but they are synthesized events.
634 switch (mClass) {
635 case eKeyboardEventClass:
636 case eCompositionEventClass:
637 case eMouseScrollEventClass:
638 case eWheelEventClass:
639 case eGestureNotifyEventClass:
640 case eSimpleGestureEventClass:
641 case eTouchEventClass:
642 case eCommandEventClass:
643 case eContentCommandEventClass:
644 return true;
645 case eMouseEventClass:
646 case eDragEventClass:
647 case ePointerEventClass:
648 return AsMouseEvent()->IsReal();
649 default:
650 return false;
654 /******************************************************************************
655 * mozilla::WidgetInputEvent
656 ******************************************************************************/
658 /* static */
659 Modifier WidgetInputEvent::GetModifier(const nsAString& aDOMKeyName) {
660 if (aDOMKeyName.EqualsLiteral("Accel")) {
661 return AccelModifier();
663 KeyNameIndex keyNameIndex = WidgetKeyboardEvent::GetKeyNameIndex(aDOMKeyName);
664 return WidgetKeyboardEvent::GetModifierForKeyName(keyNameIndex);
667 /* static */
668 Modifier WidgetInputEvent::AccelModifier() {
669 static Modifier sAccelModifier = MODIFIER_NONE;
670 if (sAccelModifier == MODIFIER_NONE) {
671 switch (StaticPrefs::ui_key_accelKey()) {
672 case dom::KeyboardEvent_Binding::DOM_VK_META:
673 case dom::KeyboardEvent_Binding::DOM_VK_WIN:
674 sAccelModifier = MODIFIER_META;
675 break;
676 case dom::KeyboardEvent_Binding::DOM_VK_ALT:
677 sAccelModifier = MODIFIER_ALT;
678 break;
679 case dom::KeyboardEvent_Binding::DOM_VK_CONTROL:
680 sAccelModifier = MODIFIER_CONTROL;
681 break;
682 default:
683 #ifdef XP_MACOSX
684 sAccelModifier = MODIFIER_META;
685 #else
686 sAccelModifier = MODIFIER_CONTROL;
687 #endif
688 break;
691 return sAccelModifier;
694 /******************************************************************************
695 * mozilla::WidgetMouseEventBase (MouseEvents.h)
696 ******************************************************************************/
698 bool WidgetMouseEventBase::InputSourceSupportsHover() const {
699 switch (mInputSource) {
700 case dom::MouseEvent_Binding::MOZ_SOURCE_MOUSE:
701 case dom::MouseEvent_Binding::MOZ_SOURCE_PEN:
702 case dom::MouseEvent_Binding::MOZ_SOURCE_ERASER:
703 return true;
704 case dom::MouseEvent_Binding::MOZ_SOURCE_TOUCH:
705 case dom::MouseEvent_Binding::MOZ_SOURCE_UNKNOWN:
706 case dom::MouseEvent_Binding::MOZ_SOURCE_KEYBOARD:
707 case dom::MouseEvent_Binding::MOZ_SOURCE_CURSOR:
708 default:
709 return false;
713 /******************************************************************************
714 * mozilla::WidgetMouseEvent (MouseEvents.h)
715 ******************************************************************************/
717 /* static */
718 bool WidgetMouseEvent::IsMiddleClickPasteEnabled() {
719 return Preferences::GetBool("middlemouse.paste", false);
722 #ifdef DEBUG
723 void WidgetMouseEvent::AssertContextMenuEventButtonConsistency() const {
724 if (mMessage != eContextMenu) {
725 return;
728 if (mContextMenuTrigger == eNormal) {
729 NS_WARNING_ASSERTION(mButton == MouseButton::eSecondary,
730 "eContextMenu events with eNormal trigger should use "
731 "secondary mouse button");
732 } else {
733 NS_WARNING_ASSERTION(mButton == MouseButton::ePrimary,
734 "eContextMenu events with non-eNormal trigger should "
735 "use primary mouse button");
738 if (mContextMenuTrigger == eControlClick) {
739 NS_WARNING_ASSERTION(IsControl(),
740 "eContextMenu events with eControlClick trigger "
741 "should return true from IsControl()");
744 #endif
746 /******************************************************************************
747 * mozilla::WidgetDragEvent (MouseEvents.h)
748 ******************************************************************************/
750 void WidgetDragEvent::InitDropEffectForTests() {
751 MOZ_ASSERT(mFlags.mIsSynthesizedForTests);
753 nsCOMPtr<nsIDragSession> session = nsContentUtils::GetDragSession();
754 if (NS_WARN_IF(!session)) {
755 return;
758 uint32_t effectAllowed = session->GetEffectAllowedForTests();
759 uint32_t desiredDropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
760 #ifdef XP_MACOSX
761 if (IsAlt()) {
762 desiredDropEffect = IsMeta() ? nsIDragService::DRAGDROP_ACTION_LINK
763 : nsIDragService::DRAGDROP_ACTION_COPY;
765 #else
766 // On Linux, we know user's intention from API, but we should use
767 // same modifiers as Windows for tests because GNOME on Ubuntu use
768 // them and that makes each test simpler.
769 if (IsControl()) {
770 desiredDropEffect = IsShift() ? nsIDragService::DRAGDROP_ACTION_LINK
771 : nsIDragService::DRAGDROP_ACTION_COPY;
772 } else if (IsShift()) {
773 desiredDropEffect = nsIDragService::DRAGDROP_ACTION_MOVE;
775 #endif // #ifdef XP_MACOSX #else
776 // First, use modifier state for preferring action which is explicitly
777 // specified by the synthesizer.
778 if (!(desiredDropEffect &= effectAllowed)) {
779 // Otherwise, use an action which is allowed at starting the session.
780 desiredDropEffect = effectAllowed;
782 if (desiredDropEffect & nsIDragService::DRAGDROP_ACTION_MOVE) {
783 session->SetDragAction(nsIDragService::DRAGDROP_ACTION_MOVE);
784 } else if (desiredDropEffect & nsIDragService::DRAGDROP_ACTION_COPY) {
785 session->SetDragAction(nsIDragService::DRAGDROP_ACTION_COPY);
786 } else if (desiredDropEffect & nsIDragService::DRAGDROP_ACTION_LINK) {
787 session->SetDragAction(nsIDragService::DRAGDROP_ACTION_LINK);
788 } else {
789 session->SetDragAction(nsIDragService::DRAGDROP_ACTION_NONE);
793 /******************************************************************************
794 * mozilla::WidgetWheelEvent (MouseEvents.h)
795 ******************************************************************************/
797 /* static */
798 double WidgetWheelEvent::ComputeOverriddenDelta(double aDelta,
799 bool aIsForVertical) {
800 if (!StaticPrefs::mousewheel_system_scroll_override_enabled()) {
801 return aDelta;
803 int32_t intFactor =
804 aIsForVertical
805 ? StaticPrefs::mousewheel_system_scroll_override_vertical_factor()
806 : StaticPrefs::mousewheel_system_scroll_override_horizontal_factor();
807 // Making the scroll speed slower doesn't make sense. So, ignore odd factor
808 // which is less than 1.0.
809 if (intFactor <= 100) {
810 return aDelta;
812 double factor = static_cast<double>(intFactor) / 100;
813 return aDelta * factor;
816 double WidgetWheelEvent::OverriddenDeltaX() const {
817 if (!mAllowToOverrideSystemScrollSpeed ||
818 mDeltaMode != dom::WheelEvent_Binding::DOM_DELTA_LINE ||
819 mCustomizedByUserPrefs) {
820 return mDeltaX;
822 return ComputeOverriddenDelta(mDeltaX, false);
825 double WidgetWheelEvent::OverriddenDeltaY() const {
826 if (!mAllowToOverrideSystemScrollSpeed ||
827 mDeltaMode != dom::WheelEvent_Binding::DOM_DELTA_LINE ||
828 mCustomizedByUserPrefs) {
829 return mDeltaY;
831 return ComputeOverriddenDelta(mDeltaY, true);
834 /******************************************************************************
835 * mozilla::WidgetKeyboardEvent (TextEvents.h)
836 ******************************************************************************/
838 #define NS_DEFINE_KEYNAME(aCPPName, aDOMKeyName) (u"" aDOMKeyName),
839 const char16_t* const WidgetKeyboardEvent::kKeyNames[] = {
840 #include "mozilla/KeyNameList.h"
842 #undef NS_DEFINE_KEYNAME
844 #define NS_DEFINE_PHYSICAL_KEY_CODE_NAME(aCPPName, aDOMCodeName) \
845 (u"" aDOMCodeName),
846 const char16_t* const WidgetKeyboardEvent::kCodeNames[] = {
847 #include "mozilla/PhysicalKeyCodeNameList.h"
849 #undef NS_DEFINE_PHYSICAL_KEY_CODE_NAME
851 WidgetKeyboardEvent::KeyNameIndexHashtable*
852 WidgetKeyboardEvent::sKeyNameIndexHashtable = nullptr;
853 WidgetKeyboardEvent::CodeNameIndexHashtable*
854 WidgetKeyboardEvent::sCodeNameIndexHashtable = nullptr;
856 void WidgetKeyboardEvent::InitAllEditCommands(
857 const Maybe<WritingMode>& aWritingMode) {
858 // If this event is synthesized for tests, we don't need to retrieve the
859 // command via the main process. So, we don't need widget and can trust
860 // the event.
861 if (!mFlags.mIsSynthesizedForTests) {
862 // If the event was created without widget, e.g., created event in chrome
863 // script, this shouldn't execute native key bindings.
864 if (NS_WARN_IF(!mWidget)) {
865 return;
868 // This event should be trusted event here and we shouldn't expose native
869 // key binding information to web contents with untrusted events.
870 if (NS_WARN_IF(!IsTrusted())) {
871 return;
874 MOZ_ASSERT(
875 XRE_IsParentProcess(),
876 "It's too expensive to retrieve all edit commands from remote process");
877 MOZ_ASSERT(!AreAllEditCommandsInitialized(),
878 "Shouldn't be called two or more times");
881 DebugOnly<bool> okIgnored = InitEditCommandsFor(
882 NativeKeyBindingsType::SingleLineEditor, aWritingMode);
883 NS_WARNING_ASSERTION(okIgnored,
884 "InitEditCommandsFor(NativeKeyBindingsType::"
885 "SingleLineEditor) failed, but ignored");
886 okIgnored =
887 InitEditCommandsFor(NativeKeyBindingsType::MultiLineEditor, aWritingMode);
888 NS_WARNING_ASSERTION(okIgnored,
889 "InitEditCommandsFor(NativeKeyBindingsType::"
890 "MultiLineEditor) failed, but ignored");
891 okIgnored =
892 InitEditCommandsFor(NativeKeyBindingsType::RichTextEditor, aWritingMode);
893 NS_WARNING_ASSERTION(okIgnored,
894 "InitEditCommandsFor(NativeKeyBindingsType::"
895 "RichTextEditor) failed, but ignored");
898 bool WidgetKeyboardEvent::InitEditCommandsFor(
899 NativeKeyBindingsType aType, const Maybe<WritingMode>& aWritingMode) {
900 bool& initialized = IsEditCommandsInitializedRef(aType);
901 if (initialized) {
902 return true;
904 nsTArray<CommandInt>& commands = EditCommandsRef(aType);
906 // If this event is synthesized for tests, we shouldn't access customized
907 // shortcut settings of the environment. Therefore, we don't need to check
908 // whether `widget` is set or not. And we can treat synthesized events are
909 // always trusted.
910 if (mFlags.mIsSynthesizedForTests) {
911 MOZ_DIAGNOSTIC_ASSERT(IsTrusted());
912 #if defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
913 // TODO: We should implement `NativeKeyBindings` for Windows and Android
914 // too in bug 1301497 for getting rid of the #if.
915 widget::NativeKeyBindings::GetEditCommandsForTests(aType, *this,
916 aWritingMode, commands);
917 #endif
918 initialized = true;
919 return true;
922 if (NS_WARN_IF(!mWidget) || NS_WARN_IF(!IsTrusted())) {
923 return false;
925 // `nsIWidget::GetEditCommands()` will retrieve `WritingMode` at selection
926 // again, but it should be almost zero-cost since `TextEventDispatcher`
927 // caches the value.
928 nsCOMPtr<nsIWidget> widget = mWidget;
929 initialized = widget->GetEditCommands(aType, *this, commands);
930 return initialized;
933 bool WidgetKeyboardEvent::ExecuteEditCommands(NativeKeyBindingsType aType,
934 DoCommandCallback aCallback,
935 void* aCallbackData) {
936 // If the event was created without widget, e.g., created event in chrome
937 // script, this shouldn't execute native key bindings.
938 if (NS_WARN_IF(!mWidget)) {
939 return false;
942 // This event should be trusted event here and we shouldn't expose native
943 // key binding information to web contents with untrusted events.
944 if (NS_WARN_IF(!IsTrusted())) {
945 return false;
948 if (!IsEditCommandsInitializedRef(aType)) {
949 Maybe<WritingMode> writingMode;
950 if (RefPtr<widget::TextEventDispatcher> textEventDispatcher =
951 mWidget->GetTextEventDispatcher()) {
952 writingMode = textEventDispatcher->MaybeQueryWritingModeAtSelection();
954 if (NS_WARN_IF(!InitEditCommandsFor(aType, writingMode))) {
955 return false;
959 const nsTArray<CommandInt>& commands = EditCommandsRef(aType);
960 if (commands.IsEmpty()) {
961 return false;
964 for (CommandInt command : commands) {
965 aCallback(static_cast<Command>(command), aCallbackData);
967 return true;
970 bool WidgetKeyboardEvent::ShouldCauseKeypressEvents() const {
971 // Currently, we don't dispatch keypress events of modifier keys and
972 // dead keys.
973 switch (mKeyNameIndex) {
974 case KEY_NAME_INDEX_Alt:
975 case KEY_NAME_INDEX_AltGraph:
976 case KEY_NAME_INDEX_CapsLock:
977 case KEY_NAME_INDEX_Control:
978 case KEY_NAME_INDEX_Fn:
979 case KEY_NAME_INDEX_FnLock:
980 // case KEY_NAME_INDEX_Hyper:
981 case KEY_NAME_INDEX_Meta:
982 case KEY_NAME_INDEX_NumLock:
983 case KEY_NAME_INDEX_ScrollLock:
984 case KEY_NAME_INDEX_Shift:
985 // case KEY_NAME_INDEX_Super:
986 case KEY_NAME_INDEX_Symbol:
987 case KEY_NAME_INDEX_SymbolLock:
988 case KEY_NAME_INDEX_Dead:
989 return false;
990 default:
991 return true;
995 static bool HasASCIIDigit(const ShortcutKeyCandidateArray& aCandidates) {
996 for (uint32_t i = 0; i < aCandidates.Length(); ++i) {
997 uint32_t ch = aCandidates[i].mCharCode;
998 if (ch >= '0' && ch <= '9') return true;
1000 return false;
1003 static bool CharsCaseInsensitiveEqual(uint32_t aChar1, uint32_t aChar2) {
1004 return aChar1 == aChar2 || (IS_IN_BMP(aChar1) && IS_IN_BMP(aChar2) &&
1005 ToLowerCase(static_cast<char16_t>(aChar1)) ==
1006 ToLowerCase(static_cast<char16_t>(aChar2)));
1009 static bool IsCaseChangeableChar(uint32_t aChar) {
1010 return IS_IN_BMP(aChar) && ToLowerCase(static_cast<char16_t>(aChar)) !=
1011 ToUpperCase(static_cast<char16_t>(aChar));
1014 void WidgetKeyboardEvent::GetShortcutKeyCandidates(
1015 ShortcutKeyCandidateArray& aCandidates) const {
1016 MOZ_ASSERT(aCandidates.IsEmpty(), "aCandidates must be empty");
1018 using ShiftState = ShortcutKeyCandidate::ShiftState;
1019 using SkipIfEarlierHandlerDisabled =
1020 ShortcutKeyCandidate::SkipIfEarlierHandlerDisabled;
1022 // ShortcutKeyCandidate::mCharCode is a candidate charCode.
1023 // ShortcutKeyCandidate::mShiftState means the mCharCode should be tried to
1024 // execute a command with/without shift key state. If this is Ignorable,
1025 // the shifted key state should be ignored. Otherwise, don't ignore the state.
1026 // the priority of the charCodes are (shift key is not pressed):
1027 // 0: PseudoCharCode()/ShiftState::MatchExactly,
1028 // 1: unshiftedCharCodes[0]/ShiftState::MatchExactly,
1029 // 2: unshiftedCharCodes[1]/ShiftState::MatchExactly...
1030 // the priority of the charCodes are (shift key is pressed):
1031 // 0: PseudoCharCode()/ShiftState::MatchExactly,
1032 // 1: shiftedCharCodes[0]/ShiftState::MatchExactly,
1033 // 2: shiftedCharCodes[0]/ShiftState::Ignorable,
1034 // 3: shiftedCharCodes[1]/ShiftState::MatchExactly,
1035 // 4: shiftedCharCodes[1]/ShiftState::Ignorable...
1036 uint32_t pseudoCharCode = PseudoCharCode();
1037 if (pseudoCharCode) {
1038 ShortcutKeyCandidate key(pseudoCharCode, ShiftState::MatchExactly,
1039 SkipIfEarlierHandlerDisabled::No);
1040 aCandidates.AppendElement(key);
1043 uint32_t len = mAlternativeCharCodes.Length();
1044 if (!IsShift()) {
1045 for (uint32_t i = 0; i < len; ++i) {
1046 uint32_t ch = mAlternativeCharCodes[i].mUnshiftedCharCode;
1047 if (!ch || ch == pseudoCharCode) {
1048 continue;
1050 ShortcutKeyCandidate key(ch, ShiftState::MatchExactly,
1051 SkipIfEarlierHandlerDisabled::No);
1052 aCandidates.AppendElement(key);
1054 // If unshiftedCharCodes doesn't have numeric but shiftedCharCode has it,
1055 // this keyboard layout is AZERTY or similar layout, probably.
1056 // In this case, Accel+[0-9] should be accessible without shift key.
1057 // However, the priority should be lowest.
1058 if (!HasASCIIDigit(aCandidates)) {
1059 for (uint32_t i = 0; i < len; ++i) {
1060 uint32_t ch = mAlternativeCharCodes[i].mShiftedCharCode;
1061 if (ch >= '0' && ch <= '9') {
1062 ShortcutKeyCandidate key(
1063 ch, ShiftState::MatchExactly,
1064 // Ctrl + `-` in the French keyboard layout should not match with
1065 // Ctrl + `6` shortcut when it's already fully zoomed out.
1066 SkipIfEarlierHandlerDisabled::Yes);
1067 aCandidates.AppendElement(key);
1068 break;
1072 } else {
1073 for (uint32_t i = 0; i < len; ++i) {
1074 uint32_t ch = mAlternativeCharCodes[i].mShiftedCharCode;
1075 if (!ch) {
1076 continue;
1079 if (ch != pseudoCharCode) {
1080 ShortcutKeyCandidate key(ch, ShiftState::MatchExactly,
1081 SkipIfEarlierHandlerDisabled::No);
1082 aCandidates.AppendElement(key);
1085 // If the char is an alphabet, the shift key state should not be
1086 // ignored. E.g., Ctrl+Shift+C should not execute Ctrl+C.
1088 // And checking the charCode is same as unshiftedCharCode too.
1089 // E.g., for Ctrl+Shift+(Plus of Numpad) should not run Ctrl+Plus.
1090 uint32_t unshiftCh = mAlternativeCharCodes[i].mUnshiftedCharCode;
1091 if (CharsCaseInsensitiveEqual(ch, unshiftCh)) {
1092 continue;
1095 // On the Hebrew keyboard layout on Windows, the unshifted char is a
1096 // localized character but the shifted char is a Latin alphabet,
1097 // then, we should not execute without the shift state. See bug 433192.
1098 if (IsCaseChangeableChar(ch)) {
1099 continue;
1102 // Setting the alternative charCode candidates for retry without shift
1103 // key state only when the shift key is pressed.
1104 ShortcutKeyCandidate key(ch, ShiftState::Ignorable,
1105 SkipIfEarlierHandlerDisabled::No);
1106 aCandidates.AppendElement(key);
1110 // Special case for "Space" key. With some keyboard layouts, "Space" with
1111 // or without Shift key causes non-ASCII space. For such keyboard layouts,
1112 // we should guarantee that the key press works as an ASCII white space key
1113 // press. However, if the space key is assigned to a function key, it
1114 // shouldn't work as a space key.
1115 if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING &&
1116 mCodeNameIndex == CODE_NAME_INDEX_Space && pseudoCharCode != ' ') {
1117 ShortcutKeyCandidate spaceKey(' ', ShiftState::MatchExactly,
1118 SkipIfEarlierHandlerDisabled::No);
1119 aCandidates.AppendElement(spaceKey);
1123 void WidgetKeyboardEvent::GetAccessKeyCandidates(
1124 nsTArray<uint32_t>& aCandidates) const {
1125 MOZ_ASSERT(aCandidates.IsEmpty(), "aCandidates must be empty");
1127 // return the lower cased charCode candidates for access keys.
1128 // the priority of the charCodes are:
1129 // 0: charCode, 1: unshiftedCharCodes[0], 2: shiftedCharCodes[0]
1130 // 3: unshiftedCharCodes[1], 4: shiftedCharCodes[1],...
1131 uint32_t pseudoCharCode = PseudoCharCode();
1132 if (pseudoCharCode) {
1133 uint32_t ch = pseudoCharCode;
1134 if (IS_IN_BMP(ch)) {
1135 ch = ToLowerCase(static_cast<char16_t>(ch));
1137 aCandidates.AppendElement(ch);
1139 for (uint32_t i = 0; i < mAlternativeCharCodes.Length(); ++i) {
1140 uint32_t ch[2] = {mAlternativeCharCodes[i].mUnshiftedCharCode,
1141 mAlternativeCharCodes[i].mShiftedCharCode};
1142 for (uint32_t j = 0; j < 2; ++j) {
1143 if (!ch[j]) {
1144 continue;
1146 if (IS_IN_BMP(ch[j])) {
1147 ch[j] = ToLowerCase(static_cast<char16_t>(ch[j]));
1149 // Don't append the charcode that was already appended.
1150 if (aCandidates.IndexOf(ch[j]) == aCandidates.NoIndex) {
1151 aCandidates.AppendElement(ch[j]);
1155 // Special case for "Space" key. With some keyboard layouts, "Space" with
1156 // or without Shift key causes non-ASCII space. For such keyboard layouts,
1157 // we should guarantee that the key press works as an ASCII white space key
1158 // press. However, if the space key is assigned to a function key, it
1159 // shouldn't work as a space key.
1160 if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING &&
1161 mCodeNameIndex == CODE_NAME_INDEX_Space && pseudoCharCode != ' ') {
1162 aCandidates.AppendElement(' ');
1166 // mask values for ui.key.chromeAccess and ui.key.contentAccess
1167 #define NS_MODIFIER_SHIFT 1
1168 #define NS_MODIFIER_CONTROL 2
1169 #define NS_MODIFIER_ALT 4
1170 #define NS_MODIFIER_META 8
1172 static Modifiers PrefFlagsToModifiers(int32_t aPrefFlags) {
1173 Modifiers result = 0;
1174 if (aPrefFlags & NS_MODIFIER_SHIFT) {
1175 result |= MODIFIER_SHIFT;
1177 if (aPrefFlags & NS_MODIFIER_CONTROL) {
1178 result |= MODIFIER_CONTROL;
1180 if (aPrefFlags & NS_MODIFIER_ALT) {
1181 result |= MODIFIER_ALT;
1183 if (aPrefFlags & NS_MODIFIER_META) {
1184 result |= MODIFIER_META;
1186 return result;
1189 bool WidgetKeyboardEvent::ModifiersMatchWithAccessKey(
1190 AccessKeyType aType) const {
1191 if (!ModifiersForAccessKeyMatching()) {
1192 return false;
1194 return ModifiersForAccessKeyMatching() == AccessKeyModifiers(aType);
1197 Modifiers WidgetKeyboardEvent::ModifiersForAccessKeyMatching() const {
1198 static const Modifiers kModifierMask =
1199 MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT | MODIFIER_META;
1200 return mModifiers & kModifierMask;
1203 /* static */
1204 Modifiers WidgetKeyboardEvent::AccessKeyModifiers(AccessKeyType aType) {
1205 switch (StaticPrefs::ui_key_generalAccessKey()) {
1206 case -1:
1207 break; // use the individual prefs
1208 case NS_VK_SHIFT:
1209 return MODIFIER_SHIFT;
1210 case NS_VK_CONTROL:
1211 return MODIFIER_CONTROL;
1212 case NS_VK_ALT:
1213 return MODIFIER_ALT;
1214 case NS_VK_META:
1215 case NS_VK_WIN:
1216 return MODIFIER_META;
1217 default:
1218 return MODIFIER_NONE;
1221 switch (aType) {
1222 case AccessKeyType::eChrome:
1223 return PrefFlagsToModifiers(StaticPrefs::ui_key_chromeAccess());
1224 case AccessKeyType::eContent:
1225 return PrefFlagsToModifiers(StaticPrefs::ui_key_contentAccess());
1226 default:
1227 return MODIFIER_NONE;
1231 /* static */
1232 void WidgetKeyboardEvent::Shutdown() {
1233 delete sKeyNameIndexHashtable;
1234 sKeyNameIndexHashtable = nullptr;
1235 delete sCodeNameIndexHashtable;
1236 sCodeNameIndexHashtable = nullptr;
1237 // Although sCommandHashtable is not a member of WidgetKeyboardEvent, but
1238 // let's delete it here since we need to do it at same time.
1239 delete sCommandHashtable;
1240 sCommandHashtable = nullptr;
1243 /* static */
1244 void WidgetKeyboardEvent::GetDOMKeyName(KeyNameIndex aKeyNameIndex,
1245 nsAString& aKeyName) {
1246 if (aKeyNameIndex >= KEY_NAME_INDEX_USE_STRING) {
1247 aKeyName.Truncate();
1248 return;
1251 MOZ_RELEASE_ASSERT(
1252 static_cast<size_t>(aKeyNameIndex) < ArrayLength(kKeyNames),
1253 "Illegal key enumeration value");
1254 aKeyName = kKeyNames[aKeyNameIndex];
1257 /* static */
1258 void WidgetKeyboardEvent::GetDOMCodeName(CodeNameIndex aCodeNameIndex,
1259 nsAString& aCodeName) {
1260 if (aCodeNameIndex >= CODE_NAME_INDEX_USE_STRING) {
1261 aCodeName.Truncate();
1262 return;
1265 MOZ_RELEASE_ASSERT(
1266 static_cast<size_t>(aCodeNameIndex) < ArrayLength(kCodeNames),
1267 "Illegal physical code enumeration value");
1269 // Generate some continuous runs of codes, rather than looking them up.
1270 if (aCodeNameIndex >= CODE_NAME_INDEX_KeyA &&
1271 aCodeNameIndex <= CODE_NAME_INDEX_KeyZ) {
1272 uint32_t index = aCodeNameIndex - CODE_NAME_INDEX_KeyA;
1273 aCodeName.AssignLiteral(u"Key");
1274 aCodeName.Append(u'A' + index);
1275 return;
1277 if (aCodeNameIndex >= CODE_NAME_INDEX_Digit0 &&
1278 aCodeNameIndex <= CODE_NAME_INDEX_Digit9) {
1279 uint32_t index = aCodeNameIndex - CODE_NAME_INDEX_Digit0;
1280 aCodeName.AssignLiteral(u"Digit");
1281 aCodeName.AppendInt(index);
1282 return;
1284 if (aCodeNameIndex >= CODE_NAME_INDEX_Numpad0 &&
1285 aCodeNameIndex <= CODE_NAME_INDEX_Numpad9) {
1286 uint32_t index = aCodeNameIndex - CODE_NAME_INDEX_Numpad0;
1287 aCodeName.AssignLiteral(u"Numpad");
1288 aCodeName.AppendInt(index);
1289 return;
1291 if (aCodeNameIndex >= CODE_NAME_INDEX_F1 &&
1292 aCodeNameIndex <= CODE_NAME_INDEX_F24) {
1293 uint32_t index = aCodeNameIndex - CODE_NAME_INDEX_F1;
1294 aCodeName.Assign(u'F');
1295 aCodeName.AppendInt(index + 1);
1296 return;
1299 aCodeName = kCodeNames[aCodeNameIndex];
1302 /* static */
1303 KeyNameIndex WidgetKeyboardEvent::GetKeyNameIndex(const nsAString& aKeyValue) {
1304 if (!sKeyNameIndexHashtable) {
1305 sKeyNameIndexHashtable = new KeyNameIndexHashtable(ArrayLength(kKeyNames));
1306 for (size_t i = 0; i < ArrayLength(kKeyNames); i++) {
1307 sKeyNameIndexHashtable->InsertOrUpdate(nsDependentString(kKeyNames[i]),
1308 static_cast<KeyNameIndex>(i));
1311 return sKeyNameIndexHashtable->MaybeGet(aKeyValue).valueOr(
1312 KEY_NAME_INDEX_USE_STRING);
1315 /* static */
1316 CodeNameIndex WidgetKeyboardEvent::GetCodeNameIndex(
1317 const nsAString& aCodeValue) {
1318 if (!sCodeNameIndexHashtable) {
1319 sCodeNameIndexHashtable =
1320 new CodeNameIndexHashtable(ArrayLength(kCodeNames));
1321 for (size_t i = 0; i < ArrayLength(kCodeNames); i++) {
1322 sCodeNameIndexHashtable->InsertOrUpdate(nsDependentString(kCodeNames[i]),
1323 static_cast<CodeNameIndex>(i));
1326 return sCodeNameIndexHashtable->MaybeGet(aCodeValue)
1327 .valueOr(CODE_NAME_INDEX_USE_STRING);
1330 /* static */
1331 uint32_t WidgetKeyboardEvent::GetFallbackKeyCodeOfPunctuationKey(
1332 CodeNameIndex aCodeNameIndex) {
1333 switch (aCodeNameIndex) {
1334 case CODE_NAME_INDEX_Semicolon: // VK_OEM_1 on Windows
1335 return dom::KeyboardEvent_Binding::DOM_VK_SEMICOLON;
1336 case CODE_NAME_INDEX_Equal: // VK_OEM_PLUS on Windows
1337 return dom::KeyboardEvent_Binding::DOM_VK_EQUALS;
1338 case CODE_NAME_INDEX_Comma: // VK_OEM_COMMA on Windows
1339 return dom::KeyboardEvent_Binding::DOM_VK_COMMA;
1340 case CODE_NAME_INDEX_Minus: // VK_OEM_MINUS on Windows
1341 return dom::KeyboardEvent_Binding::DOM_VK_HYPHEN_MINUS;
1342 case CODE_NAME_INDEX_Period: // VK_OEM_PERIOD on Windows
1343 return dom::KeyboardEvent_Binding::DOM_VK_PERIOD;
1344 case CODE_NAME_INDEX_Slash: // VK_OEM_2 on Windows
1345 return dom::KeyboardEvent_Binding::DOM_VK_SLASH;
1346 case CODE_NAME_INDEX_Backquote: // VK_OEM_3 on Windows
1347 return dom::KeyboardEvent_Binding::DOM_VK_BACK_QUOTE;
1348 case CODE_NAME_INDEX_BracketLeft: // VK_OEM_4 on Windows
1349 return dom::KeyboardEvent_Binding::DOM_VK_OPEN_BRACKET;
1350 case CODE_NAME_INDEX_Backslash: // VK_OEM_5 on Windows
1351 return dom::KeyboardEvent_Binding::DOM_VK_BACK_SLASH;
1352 case CODE_NAME_INDEX_BracketRight: // VK_OEM_6 on Windows
1353 return dom::KeyboardEvent_Binding::DOM_VK_CLOSE_BRACKET;
1354 case CODE_NAME_INDEX_Quote: // VK_OEM_7 on Windows
1355 return dom::KeyboardEvent_Binding::DOM_VK_QUOTE;
1356 case CODE_NAME_INDEX_IntlBackslash: // VK_OEM_5 on Windows (ABNT, etc)
1357 case CODE_NAME_INDEX_IntlYen: // VK_OEM_5 on Windows (JIS)
1358 case CODE_NAME_INDEX_IntlRo: // VK_OEM_102 on Windows
1359 return dom::KeyboardEvent_Binding::DOM_VK_BACK_SLASH;
1360 default:
1361 return 0;
1365 /* static */ const char* WidgetKeyboardEvent::GetCommandStr(Command aCommand) {
1366 #define NS_DEFINE_COMMAND(aName, aCommandStr) , #aCommandStr
1367 #define NS_DEFINE_COMMAND_WITH_PARAM(aName, aCommandStr, aParam) , #aCommandStr
1368 #define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName) , ""
1369 static const char* const kCommands[] = {
1370 "" // DoNothing
1371 #include "mozilla/CommandList.h"
1373 #undef NS_DEFINE_COMMAND
1374 #undef NS_DEFINE_COMMAND_WITH_PARAM
1375 #undef NS_DEFINE_COMMAND_NO_EXEC_COMMAND
1377 MOZ_RELEASE_ASSERT(static_cast<size_t>(aCommand) < ArrayLength(kCommands),
1378 "Illegal command enumeration value");
1379 return kCommands[static_cast<CommandInt>(aCommand)];
1382 /* static */
1383 uint32_t WidgetKeyboardEvent::ComputeLocationFromCodeValue(
1384 CodeNameIndex aCodeNameIndex) {
1385 // Following commented out cases are not defined in PhysicalKeyCodeNameList.h
1386 // but are defined by D3E spec. So, they should be uncommented when the
1387 // code values are defined in the header.
1388 switch (aCodeNameIndex) {
1389 case CODE_NAME_INDEX_AltLeft:
1390 case CODE_NAME_INDEX_ControlLeft:
1391 case CODE_NAME_INDEX_MetaLeft:
1392 case CODE_NAME_INDEX_ShiftLeft:
1393 return eKeyLocationLeft;
1394 case CODE_NAME_INDEX_AltRight:
1395 case CODE_NAME_INDEX_ControlRight:
1396 case CODE_NAME_INDEX_MetaRight:
1397 case CODE_NAME_INDEX_ShiftRight:
1398 return eKeyLocationRight;
1399 case CODE_NAME_INDEX_Numpad0:
1400 case CODE_NAME_INDEX_Numpad1:
1401 case CODE_NAME_INDEX_Numpad2:
1402 case CODE_NAME_INDEX_Numpad3:
1403 case CODE_NAME_INDEX_Numpad4:
1404 case CODE_NAME_INDEX_Numpad5:
1405 case CODE_NAME_INDEX_Numpad6:
1406 case CODE_NAME_INDEX_Numpad7:
1407 case CODE_NAME_INDEX_Numpad8:
1408 case CODE_NAME_INDEX_Numpad9:
1409 case CODE_NAME_INDEX_NumpadAdd:
1410 case CODE_NAME_INDEX_NumpadBackspace:
1411 case CODE_NAME_INDEX_NumpadClear:
1412 case CODE_NAME_INDEX_NumpadClearEntry:
1413 case CODE_NAME_INDEX_NumpadComma:
1414 case CODE_NAME_INDEX_NumpadDecimal:
1415 case CODE_NAME_INDEX_NumpadDivide:
1416 case CODE_NAME_INDEX_NumpadEnter:
1417 case CODE_NAME_INDEX_NumpadEqual:
1418 case CODE_NAME_INDEX_NumpadMemoryAdd:
1419 case CODE_NAME_INDEX_NumpadMemoryClear:
1420 case CODE_NAME_INDEX_NumpadMemoryRecall:
1421 case CODE_NAME_INDEX_NumpadMemoryStore:
1422 case CODE_NAME_INDEX_NumpadMemorySubtract:
1423 case CODE_NAME_INDEX_NumpadMultiply:
1424 case CODE_NAME_INDEX_NumpadParenLeft:
1425 case CODE_NAME_INDEX_NumpadParenRight:
1426 case CODE_NAME_INDEX_NumpadSubtract:
1427 return eKeyLocationNumpad;
1428 default:
1429 return eKeyLocationStandard;
1433 /* static */
1434 uint32_t WidgetKeyboardEvent::ComputeKeyCodeFromKeyNameIndex(
1435 KeyNameIndex aKeyNameIndex) {
1436 switch (aKeyNameIndex) {
1437 case KEY_NAME_INDEX_Cancel:
1438 return dom::KeyboardEvent_Binding::DOM_VK_CANCEL;
1439 case KEY_NAME_INDEX_Help:
1440 return dom::KeyboardEvent_Binding::DOM_VK_HELP;
1441 case KEY_NAME_INDEX_Backspace:
1442 return dom::KeyboardEvent_Binding::DOM_VK_BACK_SPACE;
1443 case KEY_NAME_INDEX_Tab:
1444 return dom::KeyboardEvent_Binding::DOM_VK_TAB;
1445 case KEY_NAME_INDEX_Clear:
1446 return dom::KeyboardEvent_Binding::DOM_VK_CLEAR;
1447 case KEY_NAME_INDEX_Enter:
1448 return dom::KeyboardEvent_Binding::DOM_VK_RETURN;
1449 case KEY_NAME_INDEX_Shift:
1450 return dom::KeyboardEvent_Binding::DOM_VK_SHIFT;
1451 case KEY_NAME_INDEX_Control:
1452 return dom::KeyboardEvent_Binding::DOM_VK_CONTROL;
1453 case KEY_NAME_INDEX_Alt:
1454 return dom::KeyboardEvent_Binding::DOM_VK_ALT;
1455 case KEY_NAME_INDEX_Pause:
1456 return dom::KeyboardEvent_Binding::DOM_VK_PAUSE;
1457 case KEY_NAME_INDEX_CapsLock:
1458 return dom::KeyboardEvent_Binding::DOM_VK_CAPS_LOCK;
1459 case KEY_NAME_INDEX_Hiragana:
1460 case KEY_NAME_INDEX_Katakana:
1461 case KEY_NAME_INDEX_HiraganaKatakana:
1462 case KEY_NAME_INDEX_KanaMode:
1463 return dom::KeyboardEvent_Binding::DOM_VK_KANA;
1464 case KEY_NAME_INDEX_HangulMode:
1465 return dom::KeyboardEvent_Binding::DOM_VK_HANGUL;
1466 case KEY_NAME_INDEX_Eisu:
1467 return dom::KeyboardEvent_Binding::DOM_VK_EISU;
1468 case KEY_NAME_INDEX_JunjaMode:
1469 return dom::KeyboardEvent_Binding::DOM_VK_JUNJA;
1470 case KEY_NAME_INDEX_FinalMode:
1471 return dom::KeyboardEvent_Binding::DOM_VK_FINAL;
1472 case KEY_NAME_INDEX_HanjaMode:
1473 return dom::KeyboardEvent_Binding::DOM_VK_HANJA;
1474 case KEY_NAME_INDEX_KanjiMode:
1475 return dom::KeyboardEvent_Binding::DOM_VK_KANJI;
1476 case KEY_NAME_INDEX_Escape:
1477 return dom::KeyboardEvent_Binding::DOM_VK_ESCAPE;
1478 case KEY_NAME_INDEX_Convert:
1479 return dom::KeyboardEvent_Binding::DOM_VK_CONVERT;
1480 case KEY_NAME_INDEX_NonConvert:
1481 return dom::KeyboardEvent_Binding::DOM_VK_NONCONVERT;
1482 case KEY_NAME_INDEX_Accept:
1483 return dom::KeyboardEvent_Binding::DOM_VK_ACCEPT;
1484 case KEY_NAME_INDEX_ModeChange:
1485 return dom::KeyboardEvent_Binding::DOM_VK_MODECHANGE;
1486 case KEY_NAME_INDEX_PageUp:
1487 return dom::KeyboardEvent_Binding::DOM_VK_PAGE_UP;
1488 case KEY_NAME_INDEX_PageDown:
1489 return dom::KeyboardEvent_Binding::DOM_VK_PAGE_DOWN;
1490 case KEY_NAME_INDEX_End:
1491 return dom::KeyboardEvent_Binding::DOM_VK_END;
1492 case KEY_NAME_INDEX_Home:
1493 return dom::KeyboardEvent_Binding::DOM_VK_HOME;
1494 case KEY_NAME_INDEX_ArrowLeft:
1495 return dom::KeyboardEvent_Binding::DOM_VK_LEFT;
1496 case KEY_NAME_INDEX_ArrowUp:
1497 return dom::KeyboardEvent_Binding::DOM_VK_UP;
1498 case KEY_NAME_INDEX_ArrowRight:
1499 return dom::KeyboardEvent_Binding::DOM_VK_RIGHT;
1500 case KEY_NAME_INDEX_ArrowDown:
1501 return dom::KeyboardEvent_Binding::DOM_VK_DOWN;
1502 case KEY_NAME_INDEX_Select:
1503 return dom::KeyboardEvent_Binding::DOM_VK_SELECT;
1504 case KEY_NAME_INDEX_Print:
1505 return dom::KeyboardEvent_Binding::DOM_VK_PRINT;
1506 case KEY_NAME_INDEX_Execute:
1507 return dom::KeyboardEvent_Binding::DOM_VK_EXECUTE;
1508 case KEY_NAME_INDEX_PrintScreen:
1509 return dom::KeyboardEvent_Binding::DOM_VK_PRINTSCREEN;
1510 case KEY_NAME_INDEX_Insert:
1511 return dom::KeyboardEvent_Binding::DOM_VK_INSERT;
1512 case KEY_NAME_INDEX_Delete:
1513 return dom::KeyboardEvent_Binding::DOM_VK_DELETE;
1514 case KEY_NAME_INDEX_ContextMenu:
1515 return dom::KeyboardEvent_Binding::DOM_VK_CONTEXT_MENU;
1516 case KEY_NAME_INDEX_Standby:
1517 return dom::KeyboardEvent_Binding::DOM_VK_SLEEP;
1518 case KEY_NAME_INDEX_F1:
1519 return dom::KeyboardEvent_Binding::DOM_VK_F1;
1520 case KEY_NAME_INDEX_F2:
1521 return dom::KeyboardEvent_Binding::DOM_VK_F2;
1522 case KEY_NAME_INDEX_F3:
1523 return dom::KeyboardEvent_Binding::DOM_VK_F3;
1524 case KEY_NAME_INDEX_F4:
1525 return dom::KeyboardEvent_Binding::DOM_VK_F4;
1526 case KEY_NAME_INDEX_F5:
1527 return dom::KeyboardEvent_Binding::DOM_VK_F5;
1528 case KEY_NAME_INDEX_F6:
1529 return dom::KeyboardEvent_Binding::DOM_VK_F6;
1530 case KEY_NAME_INDEX_F7:
1531 return dom::KeyboardEvent_Binding::DOM_VK_F7;
1532 case KEY_NAME_INDEX_F8:
1533 return dom::KeyboardEvent_Binding::DOM_VK_F8;
1534 case KEY_NAME_INDEX_F9:
1535 return dom::KeyboardEvent_Binding::DOM_VK_F9;
1536 case KEY_NAME_INDEX_F10:
1537 return dom::KeyboardEvent_Binding::DOM_VK_F10;
1538 case KEY_NAME_INDEX_F11:
1539 return dom::KeyboardEvent_Binding::DOM_VK_F11;
1540 case KEY_NAME_INDEX_F12:
1541 return dom::KeyboardEvent_Binding::DOM_VK_F12;
1542 case KEY_NAME_INDEX_F13:
1543 return dom::KeyboardEvent_Binding::DOM_VK_F13;
1544 case KEY_NAME_INDEX_F14:
1545 return dom::KeyboardEvent_Binding::DOM_VK_F14;
1546 case KEY_NAME_INDEX_F15:
1547 return dom::KeyboardEvent_Binding::DOM_VK_F15;
1548 case KEY_NAME_INDEX_F16:
1549 return dom::KeyboardEvent_Binding::DOM_VK_F16;
1550 case KEY_NAME_INDEX_F17:
1551 return dom::KeyboardEvent_Binding::DOM_VK_F17;
1552 case KEY_NAME_INDEX_F18:
1553 return dom::KeyboardEvent_Binding::DOM_VK_F18;
1554 case KEY_NAME_INDEX_F19:
1555 return dom::KeyboardEvent_Binding::DOM_VK_F19;
1556 case KEY_NAME_INDEX_F20:
1557 return dom::KeyboardEvent_Binding::DOM_VK_F20;
1558 case KEY_NAME_INDEX_F21:
1559 return dom::KeyboardEvent_Binding::DOM_VK_F21;
1560 case KEY_NAME_INDEX_F22:
1561 return dom::KeyboardEvent_Binding::DOM_VK_F22;
1562 case KEY_NAME_INDEX_F23:
1563 return dom::KeyboardEvent_Binding::DOM_VK_F23;
1564 case KEY_NAME_INDEX_F24:
1565 return dom::KeyboardEvent_Binding::DOM_VK_F24;
1566 case KEY_NAME_INDEX_NumLock:
1567 return dom::KeyboardEvent_Binding::DOM_VK_NUM_LOCK;
1568 case KEY_NAME_INDEX_ScrollLock:
1569 return dom::KeyboardEvent_Binding::DOM_VK_SCROLL_LOCK;
1570 case KEY_NAME_INDEX_AudioVolumeMute:
1571 return dom::KeyboardEvent_Binding::DOM_VK_VOLUME_MUTE;
1572 case KEY_NAME_INDEX_AudioVolumeDown:
1573 return dom::KeyboardEvent_Binding::DOM_VK_VOLUME_DOWN;
1574 case KEY_NAME_INDEX_AudioVolumeUp:
1575 return dom::KeyboardEvent_Binding::DOM_VK_VOLUME_UP;
1576 case KEY_NAME_INDEX_Meta:
1577 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
1578 return dom::KeyboardEvent_Binding::DOM_VK_WIN;
1579 #else
1580 return dom::KeyboardEvent_Binding::DOM_VK_META;
1581 #endif
1582 case KEY_NAME_INDEX_AltGraph:
1583 return dom::KeyboardEvent_Binding::DOM_VK_ALTGR;
1584 case KEY_NAME_INDEX_Process:
1585 return dom::KeyboardEvent_Binding::DOM_VK_PROCESSKEY;
1586 case KEY_NAME_INDEX_Attn:
1587 return dom::KeyboardEvent_Binding::DOM_VK_ATTN;
1588 case KEY_NAME_INDEX_CrSel:
1589 return dom::KeyboardEvent_Binding::DOM_VK_CRSEL;
1590 case KEY_NAME_INDEX_ExSel:
1591 return dom::KeyboardEvent_Binding::DOM_VK_EXSEL;
1592 case KEY_NAME_INDEX_EraseEof:
1593 return dom::KeyboardEvent_Binding::DOM_VK_EREOF;
1594 case KEY_NAME_INDEX_Play:
1595 return dom::KeyboardEvent_Binding::DOM_VK_PLAY;
1596 case KEY_NAME_INDEX_ZoomToggle:
1597 case KEY_NAME_INDEX_ZoomIn:
1598 case KEY_NAME_INDEX_ZoomOut:
1599 return dom::KeyboardEvent_Binding::DOM_VK_ZOOM;
1600 default:
1601 return 0;
1605 /* static */
1606 CodeNameIndex WidgetKeyboardEvent::ComputeCodeNameIndexFromKeyNameIndex(
1607 KeyNameIndex aKeyNameIndex, const Maybe<uint32_t>& aLocation) {
1608 if (aLocation.isSome() &&
1609 aLocation.value() ==
1610 dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_NUMPAD) {
1611 // On macOS, NumLock is not supported. Therefore, this handles
1612 // control key values except "Enter" only on non-macOS platforms.
1613 switch (aKeyNameIndex) {
1614 #ifndef XP_MACOSX
1615 case KEY_NAME_INDEX_Insert:
1616 return CODE_NAME_INDEX_Numpad0;
1617 case KEY_NAME_INDEX_End:
1618 return CODE_NAME_INDEX_Numpad1;
1619 case KEY_NAME_INDEX_ArrowDown:
1620 return CODE_NAME_INDEX_Numpad2;
1621 case KEY_NAME_INDEX_PageDown:
1622 return CODE_NAME_INDEX_Numpad3;
1623 case KEY_NAME_INDEX_ArrowLeft:
1624 return CODE_NAME_INDEX_Numpad4;
1625 case KEY_NAME_INDEX_Clear:
1626 // FYI: "Clear" on macOS should be DOM_KEY_LOCATION_STANDARD.
1627 return CODE_NAME_INDEX_Numpad5;
1628 case KEY_NAME_INDEX_ArrowRight:
1629 return CODE_NAME_INDEX_Numpad6;
1630 case KEY_NAME_INDEX_Home:
1631 return CODE_NAME_INDEX_Numpad7;
1632 case KEY_NAME_INDEX_ArrowUp:
1633 return CODE_NAME_INDEX_Numpad8;
1634 case KEY_NAME_INDEX_PageUp:
1635 return CODE_NAME_INDEX_Numpad9;
1636 case KEY_NAME_INDEX_Delete:
1637 return CODE_NAME_INDEX_NumpadDecimal;
1638 #endif // #ifndef XP_MACOSX
1639 case KEY_NAME_INDEX_Enter:
1640 return CODE_NAME_INDEX_NumpadEnter;
1641 default:
1642 return CODE_NAME_INDEX_UNKNOWN;
1646 if (WidgetKeyboardEvent::IsLeftOrRightModiferKeyNameIndex(aKeyNameIndex)) {
1647 if (aLocation.isSome() &&
1648 (aLocation.value() !=
1649 dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_LEFT &&
1650 aLocation.value() !=
1651 dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_RIGHT)) {
1652 return CODE_NAME_INDEX_UNKNOWN;
1654 bool isRight =
1655 aLocation.isSome() &&
1656 aLocation.value() == dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_RIGHT;
1657 switch (aKeyNameIndex) {
1658 case KEY_NAME_INDEX_Alt:
1659 return isRight ? CODE_NAME_INDEX_AltRight : CODE_NAME_INDEX_AltLeft;
1660 case KEY_NAME_INDEX_Control:
1661 return isRight ? CODE_NAME_INDEX_ControlRight
1662 : CODE_NAME_INDEX_ControlLeft;
1663 case KEY_NAME_INDEX_Shift:
1664 return isRight ? CODE_NAME_INDEX_ShiftRight : CODE_NAME_INDEX_ShiftLeft;
1665 case KEY_NAME_INDEX_Meta:
1666 return isRight ? CODE_NAME_INDEX_MetaRight : CODE_NAME_INDEX_MetaLeft;
1667 default:
1668 return CODE_NAME_INDEX_UNKNOWN;
1672 if (aLocation.isSome() &&
1673 aLocation.value() !=
1674 dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_STANDARD) {
1675 return CODE_NAME_INDEX_UNKNOWN;
1678 switch (aKeyNameIndex) {
1679 // Standard section:
1680 case KEY_NAME_INDEX_Escape:
1681 return CODE_NAME_INDEX_Escape;
1682 case KEY_NAME_INDEX_Tab:
1683 return CODE_NAME_INDEX_Tab;
1684 case KEY_NAME_INDEX_CapsLock:
1685 return CODE_NAME_INDEX_CapsLock;
1686 case KEY_NAME_INDEX_ContextMenu:
1687 return CODE_NAME_INDEX_ContextMenu;
1688 case KEY_NAME_INDEX_Backspace:
1689 return CODE_NAME_INDEX_Backspace;
1690 case KEY_NAME_INDEX_Enter:
1691 return CODE_NAME_INDEX_Enter;
1692 #ifdef XP_MACOSX
1693 // Although, macOS does not fire native key event of "Fn" key, we support
1694 // Fn key event if it's sent by other apps directly.
1695 case KEY_NAME_INDEX_Fn:
1696 return CODE_NAME_INDEX_Fn;
1697 #endif // #ifdef
1699 // Arrow Pad section:
1700 case KEY_NAME_INDEX_ArrowLeft:
1701 return CODE_NAME_INDEX_ArrowLeft;
1702 case KEY_NAME_INDEX_ArrowUp:
1703 return CODE_NAME_INDEX_ArrowUp;
1704 case KEY_NAME_INDEX_ArrowDown:
1705 return CODE_NAME_INDEX_ArrowDown;
1706 case KEY_NAME_INDEX_ArrowRight:
1707 return CODE_NAME_INDEX_ArrowRight;
1709 // Control Pad section:
1710 #ifndef XP_MACOSX
1711 case KEY_NAME_INDEX_Insert:
1712 return CODE_NAME_INDEX_Insert;
1713 #else
1714 case KEY_NAME_INDEX_Help:
1715 return CODE_NAME_INDEX_Help;
1716 #endif // #ifndef XP_MACOSX #else
1717 case KEY_NAME_INDEX_Delete:
1718 return CODE_NAME_INDEX_Delete;
1719 case KEY_NAME_INDEX_Home:
1720 return CODE_NAME_INDEX_Home;
1721 case KEY_NAME_INDEX_End:
1722 return CODE_NAME_INDEX_End;
1723 case KEY_NAME_INDEX_PageUp:
1724 return CODE_NAME_INDEX_PageUp;
1725 case KEY_NAME_INDEX_PageDown:
1726 return CODE_NAME_INDEX_PageDown;
1728 // Function keys:
1729 case KEY_NAME_INDEX_F1:
1730 return CODE_NAME_INDEX_F1;
1731 case KEY_NAME_INDEX_F2:
1732 return CODE_NAME_INDEX_F2;
1733 case KEY_NAME_INDEX_F3:
1734 return CODE_NAME_INDEX_F3;
1735 case KEY_NAME_INDEX_F4:
1736 return CODE_NAME_INDEX_F4;
1737 case KEY_NAME_INDEX_F5:
1738 return CODE_NAME_INDEX_F5;
1739 case KEY_NAME_INDEX_F6:
1740 return CODE_NAME_INDEX_F6;
1741 case KEY_NAME_INDEX_F7:
1742 return CODE_NAME_INDEX_F7;
1743 case KEY_NAME_INDEX_F8:
1744 return CODE_NAME_INDEX_F8;
1745 case KEY_NAME_INDEX_F9:
1746 return CODE_NAME_INDEX_F9;
1747 case KEY_NAME_INDEX_F10:
1748 return CODE_NAME_INDEX_F10;
1749 case KEY_NAME_INDEX_F11:
1750 return CODE_NAME_INDEX_F11;
1751 case KEY_NAME_INDEX_F12:
1752 return CODE_NAME_INDEX_F12;
1753 case KEY_NAME_INDEX_F13:
1754 return CODE_NAME_INDEX_F13;
1755 case KEY_NAME_INDEX_F14:
1756 return CODE_NAME_INDEX_F14;
1757 case KEY_NAME_INDEX_F15:
1758 return CODE_NAME_INDEX_F15;
1759 case KEY_NAME_INDEX_F16:
1760 return CODE_NAME_INDEX_F16;
1761 case KEY_NAME_INDEX_F17:
1762 return CODE_NAME_INDEX_F17;
1763 case KEY_NAME_INDEX_F18:
1764 return CODE_NAME_INDEX_F18;
1765 case KEY_NAME_INDEX_F19:
1766 return CODE_NAME_INDEX_F19;
1767 case KEY_NAME_INDEX_F20:
1768 return CODE_NAME_INDEX_F20;
1769 #ifndef XP_MACOSX
1770 case KEY_NAME_INDEX_F21:
1771 return CODE_NAME_INDEX_F21;
1772 case KEY_NAME_INDEX_F22:
1773 return CODE_NAME_INDEX_F22;
1774 case KEY_NAME_INDEX_F23:
1775 return CODE_NAME_INDEX_F23;
1776 case KEY_NAME_INDEX_F24:
1777 return CODE_NAME_INDEX_F24;
1778 case KEY_NAME_INDEX_Pause:
1779 return CODE_NAME_INDEX_Pause;
1780 case KEY_NAME_INDEX_PrintScreen:
1781 return CODE_NAME_INDEX_PrintScreen;
1782 case KEY_NAME_INDEX_ScrollLock:
1783 return CODE_NAME_INDEX_ScrollLock;
1784 #endif // #ifndef XP_MACOSX
1786 // NumLock key:
1787 #ifndef XP_MACOSX
1788 case KEY_NAME_INDEX_NumLock:
1789 return CODE_NAME_INDEX_NumLock;
1790 #else
1791 case KEY_NAME_INDEX_Clear:
1792 return CODE_NAME_INDEX_NumLock;
1793 #endif // #ifndef XP_MACOSX #else
1795 // Media keys:
1796 case KEY_NAME_INDEX_AudioVolumeDown:
1797 return CODE_NAME_INDEX_VolumeDown;
1798 case KEY_NAME_INDEX_AudioVolumeMute:
1799 return CODE_NAME_INDEX_VolumeMute;
1800 case KEY_NAME_INDEX_AudioVolumeUp:
1801 return CODE_NAME_INDEX_VolumeUp;
1802 #ifndef XP_MACOSX
1803 case KEY_NAME_INDEX_BrowserBack:
1804 return CODE_NAME_INDEX_BrowserBack;
1805 case KEY_NAME_INDEX_BrowserFavorites:
1806 return CODE_NAME_INDEX_BrowserFavorites;
1807 case KEY_NAME_INDEX_BrowserForward:
1808 return CODE_NAME_INDEX_BrowserForward;
1809 case KEY_NAME_INDEX_BrowserRefresh:
1810 return CODE_NAME_INDEX_BrowserRefresh;
1811 case KEY_NAME_INDEX_BrowserSearch:
1812 return CODE_NAME_INDEX_BrowserSearch;
1813 case KEY_NAME_INDEX_BrowserStop:
1814 return CODE_NAME_INDEX_BrowserStop;
1815 case KEY_NAME_INDEX_MediaPlayPause:
1816 return CODE_NAME_INDEX_MediaPlayPause;
1817 case KEY_NAME_INDEX_MediaStop:
1818 return CODE_NAME_INDEX_MediaStop;
1819 case KEY_NAME_INDEX_MediaTrackNext:
1820 return CODE_NAME_INDEX_MediaTrackNext;
1821 case KEY_NAME_INDEX_MediaTrackPrevious:
1822 return CODE_NAME_INDEX_MediaTrackPrevious;
1823 case KEY_NAME_INDEX_LaunchApplication1:
1824 return CODE_NAME_INDEX_LaunchApp1;
1825 #endif // #ifndef XP_MACOSX
1827 // Only Windows and GTK supports the following multimedia keys.
1828 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
1829 case KEY_NAME_INDEX_BrowserHome:
1830 return CODE_NAME_INDEX_BrowserHome;
1831 case KEY_NAME_INDEX_LaunchApplication2:
1832 return CODE_NAME_INDEX_LaunchApp2;
1833 #endif // #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
1835 // Only GTK and Android supports the following multimedia keys.
1836 #if defined(MOZ_WIDGET_GTK) || defined(ANDROID)
1837 case KEY_NAME_INDEX_Eject:
1838 return CODE_NAME_INDEX_Eject;
1839 case KEY_NAME_INDEX_WakeUp:
1840 return CODE_NAME_INDEX_WakeUp;
1841 #endif // #if defined(MOZ_WIDGET_GTK) || defined(ANDROID)
1843 // Only Windows does not support Help key (and macOS handled above).
1844 #if !defined(XP_WIN) && !defined(XP_MACOSX)
1845 case KEY_NAME_INDEX_Help:
1846 return CODE_NAME_INDEX_Help;
1847 #endif // #if !defined(XP_WIN) && !defined(XP_MACOSX)
1849 // IME specific keys:
1850 #ifdef XP_WIN
1851 case KEY_NAME_INDEX_Convert:
1852 return CODE_NAME_INDEX_Convert;
1853 case KEY_NAME_INDEX_NonConvert:
1854 return CODE_NAME_INDEX_NonConvert;
1855 case KEY_NAME_INDEX_Alphanumeric:
1856 return CODE_NAME_INDEX_CapsLock;
1857 case KEY_NAME_INDEX_KanaMode:
1858 case KEY_NAME_INDEX_Romaji:
1859 case KEY_NAME_INDEX_Katakana:
1860 case KEY_NAME_INDEX_Hiragana:
1861 return CODE_NAME_INDEX_KanaMode;
1862 case KEY_NAME_INDEX_Hankaku:
1863 case KEY_NAME_INDEX_Zenkaku:
1864 case KEY_NAME_INDEX_KanjiMode:
1865 return CODE_NAME_INDEX_Backquote;
1866 case KEY_NAME_INDEX_HanjaMode:
1867 return CODE_NAME_INDEX_Lang2;
1868 case KEY_NAME_INDEX_HangulMode:
1869 return CODE_NAME_INDEX_Lang1;
1870 #endif // #ifdef XP_WIN
1872 #ifdef MOZ_WIDGET_GTK
1873 case KEY_NAME_INDEX_Convert:
1874 return CODE_NAME_INDEX_Convert;
1875 case KEY_NAME_INDEX_NonConvert:
1876 return CODE_NAME_INDEX_NonConvert;
1877 case KEY_NAME_INDEX_Alphanumeric:
1878 return CODE_NAME_INDEX_CapsLock;
1879 case KEY_NAME_INDEX_HiraganaKatakana:
1880 return CODE_NAME_INDEX_KanaMode;
1881 case KEY_NAME_INDEX_ZenkakuHankaku:
1882 return CODE_NAME_INDEX_Backquote;
1883 #endif // #ifdef MOZ_WIDGET_GTK
1885 #ifdef ANDROID
1886 case KEY_NAME_INDEX_Convert:
1887 return CODE_NAME_INDEX_Convert;
1888 case KEY_NAME_INDEX_NonConvert:
1889 return CODE_NAME_INDEX_NonConvert;
1890 case KEY_NAME_INDEX_HiraganaKatakana:
1891 return CODE_NAME_INDEX_KanaMode;
1892 case KEY_NAME_INDEX_ZenkakuHankaku:
1893 return CODE_NAME_INDEX_Backquote;
1894 case KEY_NAME_INDEX_Eisu:
1895 return CODE_NAME_INDEX_Lang2;
1896 case KEY_NAME_INDEX_KanjiMode:
1897 return CODE_NAME_INDEX_Lang1;
1898 #endif // #ifdef ANDROID
1900 #ifdef XP_MACOSX
1901 case KEY_NAME_INDEX_Eisu:
1902 return CODE_NAME_INDEX_Lang2;
1903 case KEY_NAME_INDEX_KanjiMode:
1904 return CODE_NAME_INDEX_Lang1;
1905 #endif // #ifdef XP_MACOSX
1907 default:
1908 return CODE_NAME_INDEX_UNKNOWN;
1912 /* static */
1913 Modifier WidgetKeyboardEvent::GetModifierForKeyName(
1914 KeyNameIndex aKeyNameIndex) {
1915 switch (aKeyNameIndex) {
1916 case KEY_NAME_INDEX_Alt:
1917 return MODIFIER_ALT;
1918 case KEY_NAME_INDEX_AltGraph:
1919 return MODIFIER_ALTGRAPH;
1920 case KEY_NAME_INDEX_CapsLock:
1921 return MODIFIER_CAPSLOCK;
1922 case KEY_NAME_INDEX_Control:
1923 return MODIFIER_CONTROL;
1924 case KEY_NAME_INDEX_Fn:
1925 return MODIFIER_FN;
1926 case KEY_NAME_INDEX_FnLock:
1927 return MODIFIER_FNLOCK;
1928 // case KEY_NAME_INDEX_Hyper:
1929 case KEY_NAME_INDEX_Meta:
1930 return MODIFIER_META;
1931 case KEY_NAME_INDEX_NumLock:
1932 return MODIFIER_NUMLOCK;
1933 case KEY_NAME_INDEX_ScrollLock:
1934 return MODIFIER_SCROLLLOCK;
1935 case KEY_NAME_INDEX_Shift:
1936 return MODIFIER_SHIFT;
1937 // case KEY_NAME_INDEX_Super:
1938 case KEY_NAME_INDEX_Symbol:
1939 return MODIFIER_SYMBOL;
1940 case KEY_NAME_INDEX_SymbolLock:
1941 return MODIFIER_SYMBOLLOCK;
1942 default:
1943 return MODIFIER_NONE;
1947 /* static */
1948 bool WidgetKeyboardEvent::IsLockableModifier(KeyNameIndex aKeyNameIndex) {
1949 switch (aKeyNameIndex) {
1950 case KEY_NAME_INDEX_CapsLock:
1951 case KEY_NAME_INDEX_FnLock:
1952 case KEY_NAME_INDEX_NumLock:
1953 case KEY_NAME_INDEX_ScrollLock:
1954 case KEY_NAME_INDEX_SymbolLock:
1955 return true;
1956 default:
1957 return false;
1961 /******************************************************************************
1962 * mozilla::InternalEditorInputEvent (TextEvents.h)
1963 ******************************************************************************/
1965 #define NS_DEFINE_INPUTTYPE(aCPPName, aDOMName) (u"" aDOMName),
1966 const char16_t* const InternalEditorInputEvent::kInputTypeNames[] = {
1967 #include "mozilla/InputTypeList.h"
1969 #undef NS_DEFINE_INPUTTYPE
1971 InternalEditorInputEvent::InputTypeHashtable*
1972 InternalEditorInputEvent::sInputTypeHashtable = nullptr;
1974 /* static */
1975 void InternalEditorInputEvent::Shutdown() {
1976 delete sInputTypeHashtable;
1977 sInputTypeHashtable = nullptr;
1980 /* static */
1981 void InternalEditorInputEvent::GetDOMInputTypeName(EditorInputType aInputType,
1982 nsAString& aInputTypeName) {
1983 if (static_cast<size_t>(aInputType) >=
1984 static_cast<size_t>(EditorInputType::eUnknown)) {
1985 aInputTypeName.Truncate();
1986 return;
1989 MOZ_RELEASE_ASSERT(
1990 static_cast<size_t>(aInputType) < ArrayLength(kInputTypeNames),
1991 "Illegal input type enumeration value");
1992 aInputTypeName.Assign(kInputTypeNames[static_cast<size_t>(aInputType)]);
1995 /* static */
1996 EditorInputType InternalEditorInputEvent::GetEditorInputType(
1997 const nsAString& aInputType) {
1998 if (aInputType.IsEmpty()) {
1999 return EditorInputType::eUnknown;
2002 if (!sInputTypeHashtable) {
2003 sInputTypeHashtable = new InputTypeHashtable(ArrayLength(kInputTypeNames));
2004 for (size_t i = 0; i < ArrayLength(kInputTypeNames); i++) {
2005 sInputTypeHashtable->InsertOrUpdate(nsDependentString(kInputTypeNames[i]),
2006 static_cast<EditorInputType>(i));
2009 return sInputTypeHashtable->MaybeGet(aInputType)
2010 .valueOr(EditorInputType::eUnknown);
2013 } // namespace mozilla