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