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