/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
bool IsPointerEventMessage(EventMessage aMessage) { switch (aMessage) { case ePointerDown: case ePointerMove: case ePointerUp: case ePointerCancel: case ePointerOver: case ePointerOut: case ePointerEnter: case ePointerLeave: case ePointerGotCapture: case ePointerLostCapture: case ePointerClick: case ePointerAuxClick: case eContextMenu: returntrue; default: returnfalse;
}
}
bool IsForbiddenDispatchingToNonElementContent(EventMessage aMessage) { switch (aMessage) { // Keyboard event target should be an Element node case eKeyDown: case eKeyUp: case eKeyPress: // Mouse event target should be an Element node case eMouseMove: case eMouseUp: case eMouseDown: case eMouseEnterIntoWidget: case eMouseExitFromWidget: case eMouseDoubleClick: case eMouseActivate: case eMouseOver: case eMouseOut: case eMouseHitTest: case eMouseEnter: case eMouseLeave: case eMouseTouchDrag: case eMouseLongTap: case eMouseExploreByTouch: // Pointer event target should be an Element node case ePointerClick: case ePointerAuxClick: case ePointerMove: case ePointerUp: case ePointerDown: case ePointerOver: case ePointerOut: case ePointerEnter: case ePointerLeave: case ePointerCancel: case ePointerGotCapture: case ePointerLostCapture: case eContextMenu: // Drag event target should be an Element node case eDragEnter: case eDragOver: case eDragExit: case eDrag: case eDragEnd: case eDragStart: case eDrop: case eDragLeave: case eQueryDropTargetHittest: // case mouse wheel related message target should be an Element node case eLegacyMouseLineOrPageScroll: case eLegacyMousePixelScroll: case eWheel: // Composition event message target should be an Element node case eCompositionStart: case eCompositionEnd: case eCompositionUpdate: case eCompositionChange: case eCompositionCommitAsIs: case eCompositionCommit: case eCompositionCommitRequestHandled: // Gesture event target should be an Element node case eSwipeGestureMayStart: case eSwipeGestureStart: case eSwipeGestureUpdate: case eSwipeGestureEnd: case eSwipeGesture: case eMagnifyGestureStart: case eMagnifyGestureUpdate: case eMagnifyGesture: case eRotateGestureStart: case eRotateGestureUpdate: case eRotateGesture: case eTapGesture: case ePressTapGesture: case eEdgeUIStarted: case eEdgeUICanceled: case eEdgeUICompleted: // Touch event target should be an Element node case eTouchStart: case eTouchMove: case eTouchEnd: case eTouchCancel: case eTouchPointerCancel: returntrue;
default: return nsPrintfCString("Invalid DOM keyCode (0x%08X)", aKeyCode);
}
}
/****************************************************************************** * non class method implementation
******************************************************************************/
// Special cases for "cmd_align". It's mapped to multiple internal commands // with additional param. Therefore, we cannot handle it with the hashtable. if (!strcmp(aCommandName, "cmd_align")) { if (!aCommandParams) { // Note that if this is called by EditorCommand::IsCommandEnabled(), // it cannot set aCommandParams. So, don't warn in this case even though // this is illegal case for DoCommandParams(). return Command::FormatJustify;
}
nsAutoCString cValue;
nsresult rv = aCommandParams->GetCString("state_attribute", cValue); if (NS_FAILED(rv)) {
nsString value; // Avoid copying the string buffer with using nsString.
rv = aCommandParams->GetString("state_attribute", value); if (NS_FAILED(rv)) { return Command::FormatJustifyNone;
}
CopyUTF16toUTF8(value, cValue);
} if (cValue.LowerCaseEqualsASCII("left")) { return Command::FormatJustifyLeft;
} if (cValue.LowerCaseEqualsASCII("right")) { return Command::FormatJustifyRight;
} if (cValue.LowerCaseEqualsASCII("center")) { return Command::FormatJustifyCenter;
} if (cValue.LowerCaseEqualsASCII("justify")) { return Command::FormatJustifyFull;
} if (cValue.IsEmpty()) { return Command::FormatJustifyNone;
} return Command::DoNothing;
}
if (!sCommandHashtable) {
sCommandHashtable = new nsTHashMap<nsDepCharHashKey, Command>(); #define NS_DEFINE_COMMAND(aName, aCommandStr) \
sCommandHashtable->InsertOrUpdate(#aCommandStr, Command::aName);
bool WidgetEvent::HasMouseEventMessage() const { switch (mMessage) { case eMouseDown: case eMouseUp: case eMouseDoubleClick: case eMouseEnterIntoWidget: case eMouseExitFromWidget: case eMouseActivate: case eMouseOver: case eMouseOut: case eMouseHitTest: case eMouseMove: returntrue; // TODO: Perhaps, we should rename this method. case ePointerClick: case ePointerAuxClick: returntrue; default: returnfalse;
}
}
bool WidgetEvent::HasDragEventMessage() const { switch (mMessage) { case eDragEnter: case eDragOver: case eDragExit: case eDrag: case eDragEnd: case eDragStart: case eDrop: case eDragLeave: returntrue; default: returnfalse;
}
}
/* static */ bool WidgetEvent::IsKeyEventMessage(EventMessage aMessage) { switch (aMessage) { case eKeyDown: case eKeyPress: case eKeyUp: case eAccessKeyNotFound: returntrue; default: returnfalse;
}
}
bool WidgetEvent::HasIMEEventMessage() const { switch (mMessage) { case eCompositionStart: case eCompositionEnd: case eCompositionUpdate: case eCompositionChange: case eCompositionCommitAsIs: case eCompositionCommit: returntrue; default: returnfalse;
}
}
/****************************************************************************** * mozilla::WidgetEvent * * Specific event checking methods.
******************************************************************************/
bool WidgetEvent::CanBeSentToRemoteProcess() const { // If this event is explicitly marked as shouldn't be sent to remote process, // just return false. if (IsCrossProcessForwardingStopped()) { returnfalse;
}
switch (mMessage) { case eMouseDown: case eMouseUp: case eMouseMove: case eMouseExploreByTouch: case eContextMenu: case eMouseEnterIntoWidget: case eMouseExitFromWidget: case eMouseTouchDrag: case eTouchStart: case eTouchMove: case eTouchEnd: case eTouchCancel: case eDragOver: case eDragExit: case eDrop: returntrue; default: returnfalse;
}
}
bool WidgetEvent::WillBeSentToRemoteProcess() const { // This event won't be posted to remote process if it's already explicitly // stopped. if (IsCrossProcessForwardingStopped()) { returnfalse;
}
// When mOriginalTarget is nullptr, this method shouldn't be used. if (NS_WARN_IF(!mOriginalTarget)) { returnfalse;
}
bool WidgetEvent::IsAllowedToDispatchDOMEvent() const { switch (mClass) { case eMouseEventClass: if (mMessage == eMouseTouchDrag) { returnfalse;
}
[[fallthrough]]; case ePointerEventClass: // We want synthesized mouse moves to cause mouseover and mouseout // DOM events (EventStateManager::PreHandleEvent), but not mousemove // DOM events. // Synthesized button up events also do not cause DOM events because they // do not have a reliable mRefPoint. return AsMouseEvent()->mReason == WidgetMouseEvent::eReal;
case eWheelEventClass: { // wheel event whose all delta values are zero by user pref applied, it // shouldn't cause a DOM event. const WidgetWheelEvent* wheelEvent = AsWheelEvent(); return wheelEvent->mDeltaX != 0.0 || wheelEvent->mDeltaY != 0.0 ||
wheelEvent->mDeltaZ != 0.0;
} case eTouchEventClass: return mMessage != eTouchPointerCancel; // Following events are handled in EventStateManager, so, we don't need to // dispatch DOM event for them into the DOM tree. case eQueryContentEventClass: case eSelectionEventClass: case eContentCommandEventClass: returnfalse;
default: returntrue;
}
}
bool WidgetEvent::IsAllowedToDispatchInSystemGroup() const { // We don't expect to implement default behaviors with pointer events because // if we do, prevent default on mouse events can't prevent default behaviors // anymore. return mClass != ePointerEventClass ||
IsPointerEventMessageOriginallyMouseEventMessage(mMessage);
}
// We suppress the pointer events if it is not primary for fingerprinting // resistance. It is because of that we want to spoof any pointer event // into a mouse pointer event and the mouse pointer event only has // isPrimary as true. return !pointerEvent->mIsPrimary;
} default: returnfalse;
}
}
bool WidgetEvent::AllowFlushingPendingNotifications() const { if (mClass != eQueryContentEventClass) { returntrue;
} // If the dispatcher does not want a flush of pending notifications, it may // be caused by that it's unsafe. Therefore, we should allow handlers to // flush pending things only when the dispatcher requires the latest content // layout. return AsQueryContentEvent()->mNeedsToFlushLayout;
}
void WidgetEvent::PreventDefault(bool aCalledByDefaultHandler,
nsIPrincipal* aPrincipal) { if (mMessage == ePointerDown) { if (aCalledByDefaultHandler) { // Shouldn't prevent default on pointerdown by default handlers to stop // firing legacy mouse events. Use MOZ_ASSERT to catch incorrect usages // in debug builds.
MOZ_ASSERT(false); return;
} if (aPrincipal) {
nsAutoString addonId;
Unused << NS_WARN_IF(NS_FAILED(aPrincipal->GetAddonId(addonId))); if (!addonId.IsEmpty()) { // Ignore the case that it's called by a web extension. return;
}
}
}
mFlags.PreventDefault(aCalledByDefaultHandler);
}
bool WidgetEvent::IsUserAction() const { if (!IsTrusted()) { returnfalse;
} // FYI: eMouseScrollEventClass and ePointerEventClass represent // user action but they are synthesized events. switch (mClass) { case eKeyboardEventClass: case eCompositionEventClass: case eMouseScrollEventClass: case eWheelEventClass: case eGestureNotifyEventClass: case eSimpleGestureEventClass: case eTouchEventClass: case eCommandEventClass: case eContentCommandEventClass: returntrue; case eMouseEventClass: case eDragEventClass: case ePointerEventClass: return AsMouseEvent()->IsReal(); default: returnfalse;
}
}
bool WidgetMouseEventBase::InputSourceSupportsHover() const { switch (mInputSource) { case dom::MouseEvent_Binding::MOZ_SOURCE_MOUSE: case dom::MouseEvent_Binding::MOZ_SOURCE_PEN: case dom::MouseEvent_Binding::MOZ_SOURCE_ERASER: returntrue; case dom::MouseEvent_Binding::MOZ_SOURCE_TOUCH: case dom::MouseEvent_Binding::MOZ_SOURCE_UNKNOWN: case dom::MouseEvent_Binding::MOZ_SOURCE_KEYBOARD: case dom::MouseEvent_Binding::MOZ_SOURCE_CURSOR: default: returnfalse;
}
}
bool WidgetMouseEventBase::DOMEventShouldUseFractionalCoords() const { if (!StaticPrefs::dom_event_pointer_fractional_coordinates_enabled()) { returnfalse; // We completely don't support fractional coordinates
} // If we support fractional coordinates only for PointerEvent, the spec // recommend that `click`, `auxclick` and `contextmenu` keep using integer // coordinates. // https://w3c.github.io/pointerevents/#event-coordinates if (mClass == ePointerEventClass && mMessage != ePointerClick &&
mMessage != ePointerAuxClick && mMessage != eContextMenu) { returntrue;
} // Untrusted events can be initialized with double values. However, Chrome // returns integer coordinates for non-PointerEvent instances, `click`, // `auxclick` and `contextmenu`. Therefore, it may be risky to allow // fractional coordinates for all untrusted events right now because web apps // may initialize untrusted events with quotients. // https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/events/pointer_event.h;l=59-91;drc=80c2637874588837a2d656dbd79ad8f227dc67e8 // https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/events/pointer_event.cc;l=110-117;drc=8e948282d37c0e119e3102236878d6f4d5052c16 if (!IsTrusted()) { return StaticPrefs::
dom_event_mouse_fractional_coordinates_untrusted_enabled();
} // CSSOM suggested that MouseEvent interface can treat fractional values in // all instances. However, it's risky for backward compatibility. Therefore, // we don't have a plan to enable it for now. return MOZ_UNLIKELY(
StaticPrefs::dom_event_mouse_fractional_coordinates_trusted_enabled());
}
nsCOMPtr<nsIDragSession> session = nsContentUtils::GetDragSession(mWidget); if (NS_WARN_IF(!session)) { return;
}
uint32_t effectAllowed = session->GetEffectAllowedForTests();
uint32_t desiredDropEffect = nsIDragService::DRAGDROP_ACTION_NONE; #ifdef XP_MACOSX if (IsAlt()) {
desiredDropEffect = IsMeta() ? nsIDragService::DRAGDROP_ACTION_LINK
: nsIDragService::DRAGDROP_ACTION_COPY;
} #else // On Linux, we know user's intention from API, but we should use // same modifiers as Windows for tests because GNOME on Ubuntu use // them and that makes each test simpler. if (IsControl()) {
desiredDropEffect = IsShift() ? nsIDragService::DRAGDROP_ACTION_LINK
: nsIDragService::DRAGDROP_ACTION_COPY;
} elseif (IsShift()) {
desiredDropEffect = nsIDragService::DRAGDROP_ACTION_MOVE;
} #endif// #ifdef XP_MACOSX #else // First, use modifier state for preferring action which is explicitly // specified by the synthesizer. if (!(desiredDropEffect &= effectAllowed)) { // Otherwise, use an action which is allowed at starting the session.
desiredDropEffect = effectAllowed;
} if (desiredDropEffect & nsIDragService::DRAGDROP_ACTION_MOVE) {
session->SetDragAction(nsIDragService::DRAGDROP_ACTION_MOVE);
} elseif (desiredDropEffect & nsIDragService::DRAGDROP_ACTION_COPY) {
session->SetDragAction(nsIDragService::DRAGDROP_ACTION_COPY);
} elseif (desiredDropEffect & nsIDragService::DRAGDROP_ACTION_LINK) {
session->SetDragAction(nsIDragService::DRAGDROP_ACTION_LINK);
} else {
session->SetDragAction(nsIDragService::DRAGDROP_ACTION_NONE);
}
}
void WidgetKeyboardEvent::InitAllEditCommands( const Maybe<WritingMode>& aWritingMode) { // If this event is synthesized for tests, we don't need to retrieve the // command via the main process. So, we don't need widget and can trust // the event. if (!mFlags.mIsSynthesizedForTests) { // If the event was created without widget, e.g., created event in chrome // script, this shouldn't execute native key bindings. if (NS_WARN_IF(!mWidget)) { return;
}
// This event should be trusted event here and we shouldn't expose native // key binding information to web contents with untrusted events. if (NS_WARN_IF(!IsTrusted())) { return;
}
MOZ_ASSERT(
XRE_IsParentProcess(), "It's too expensive to retrieve all edit commands from remote process");
MOZ_ASSERT(!AreAllEditCommandsInitialized(), "Shouldn't be called two or more times");
}
// If this event is synthesized for tests, we shouldn't access customized // shortcut settings of the environment. Therefore, we don't need to check // whether `widget` is set or not. And we can treat synthesized events are // always trusted. if (mFlags.mIsSynthesizedForTests) {
MOZ_DIAGNOSTIC_ASSERT(IsTrusted()); #ifdefined(MOZ_WIDGET_GTK) || defined(XP_MACOSX) // TODO: We should implement `NativeKeyBindings` for Windows and Android // too in bug 1301497 for getting rid of the #if.
widget::NativeKeyBindings::GetEditCommandsForTests(aType, *this,
aWritingMode, commands); #endif
initialized = true; returntrue;
}
if (NS_WARN_IF(!mWidget) || NS_WARN_IF(!IsTrusted())) { returnfalse;
} // `nsIWidget::GetEditCommands()` will retrieve `WritingMode` at selection // again, but it should be almost zero-cost since `TextEventDispatcher` // caches the value.
nsCOMPtr<nsIWidget> widget = mWidget;
initialized = widget->GetEditCommands(aType, *this, commands); return initialized;
}
bool WidgetKeyboardEvent::ExecuteEditCommands(NativeKeyBindingsType aType,
DoCommandCallback aCallback, void* aCallbackData) { // If the event was created without widget, e.g., created event in chrome // script, this shouldn't execute native key bindings. if (NS_WARN_IF(!mWidget)) { returnfalse;
}
// This event should be trusted event here and we shouldn't expose native // key binding information to web contents with untrusted events. if (NS_WARN_IF(!IsTrusted())) { returnfalse;
}
if (!IsEditCommandsInitializedRef(aType)) {
Maybe<WritingMode> writingMode; if (RefPtr<widget::TextEventDispatcher> textEventDispatcher =
mWidget->GetTextEventDispatcher()) {
writingMode = textEventDispatcher->MaybeQueryWritingModeAtSelection();
} if (NS_WARN_IF(!InitEditCommandsFor(aType, writingMode))) { returnfalse;
}
}
const nsTArray<CommandInt>& commands = EditCommandsRef(aType); if (commands.IsEmpty()) { returnfalse;
}
bool WidgetKeyboardEvent::ShouldCauseKeypressEvents() const { // Currently, we don't dispatch keypress events of modifier keys and // dead keys. switch (mKeyNameIndex) { case KEY_NAME_INDEX_Alt: case KEY_NAME_INDEX_AltGraph: case KEY_NAME_INDEX_CapsLock: case KEY_NAME_INDEX_Control: case KEY_NAME_INDEX_Fn: case KEY_NAME_INDEX_FnLock: // case KEY_NAME_INDEX_Hyper: case KEY_NAME_INDEX_Meta: case KEY_NAME_INDEX_NumLock: case KEY_NAME_INDEX_ScrollLock: case KEY_NAME_INDEX_Shift: // case KEY_NAME_INDEX_Super: case KEY_NAME_INDEX_Symbol: case KEY_NAME_INDEX_SymbolLock: case KEY_NAME_INDEX_Dead: returnfalse; default: returntrue;
}
}
staticbool HasASCIIDigit(const ShortcutKeyCandidateArray& aCandidates) { for (uint32_t i = 0; i < aCandidates.Length(); ++i) {
uint32_t ch = aCandidates[i].mCharCode; if (ch >= '0' && ch <= '9') returntrue;
} returnfalse;
}
void WidgetKeyboardEvent::GetShortcutKeyCandidates(
ShortcutKeyCandidateArray& aCandidates) const {
MOZ_ASSERT(aCandidates.IsEmpty(), "aCandidates must be empty");
using ShiftState = ShortcutKeyCandidate::ShiftState; using SkipIfEarlierHandlerDisabled =
ShortcutKeyCandidate::SkipIfEarlierHandlerDisabled;
// ShortcutKeyCandidate::mCharCode is a candidate charCode. // ShortcutKeyCandidate::mShiftState means the mCharCode should be tried to // execute a command with/without shift key state. If this is Ignorable, // the shifted key state should be ignored. Otherwise, don't ignore the state. // the priority of the charCodes are (shift key is not pressed): // 0: PseudoCharCode()/ShiftState::MatchExactly, // 1: unshiftedCharCodes[0]/ShiftState::MatchExactly, // 2: unshiftedCharCodes[1]/ShiftState::MatchExactly... // the priority of the charCodes are (shift key is pressed): // 0: PseudoCharCode()/ShiftState::MatchExactly, // 1: shiftedCharCodes[0]/ShiftState::MatchExactly, // 2: shiftedCharCodes[0]/ShiftState::Ignorable, // 3: shiftedCharCodes[1]/ShiftState::MatchExactly, // 4: shiftedCharCodes[1]/ShiftState::Ignorable...
uint32_t pseudoCharCode = PseudoCharCode(); if (pseudoCharCode) {
ShortcutKeyCandidate key(pseudoCharCode, ShiftState::MatchExactly,
SkipIfEarlierHandlerDisabled::No);
aCandidates.AppendElement(key);
}
uint32_t len = mAlternativeCharCodes.Length(); if (!IsShift()) { for (uint32_t i = 0; i < len; ++i) {
uint32_t ch = mAlternativeCharCodes[i].mUnshiftedCharCode; if (!ch || ch == pseudoCharCode) { continue;
}
ShortcutKeyCandidate key(ch, ShiftState::MatchExactly,
SkipIfEarlierHandlerDisabled::No);
aCandidates.AppendElement(key);
} // If unshiftedCharCodes doesn't have numeric but shiftedCharCode has it, // this keyboard layout is AZERTY or similar layout, probably. // In this case, Accel+[0-9] should be accessible without shift key. // However, the priority should be lowest. if (!HasASCIIDigit(aCandidates)) { for (uint32_t i = 0; i < len; ++i) {
uint32_t ch = mAlternativeCharCodes[i].mShiftedCharCode; if (ch >= '0' && ch <= '9') {
ShortcutKeyCandidate key(
ch, ShiftState::MatchExactly, // Ctrl + `-` in the French keyboard layout should not match with // Ctrl + `6` shortcut when it's already fully zoomed out.
SkipIfEarlierHandlerDisabled::Yes);
aCandidates.AppendElement(key); break;
}
}
}
} else { for (uint32_t i = 0; i < len; ++i) {
uint32_t ch = mAlternativeCharCodes[i].mShiftedCharCode; if (!ch) { continue;
}
// If the char is an alphabet, the shift key state should not be // ignored. E.g., Ctrl+Shift+C should not execute Ctrl+C.
// And checking the charCode is same as unshiftedCharCode too. // E.g., for Ctrl+Shift+(Plus of Numpad) should not run Ctrl+Plus.
uint32_t unshiftCh = mAlternativeCharCodes[i].mUnshiftedCharCode; if (CharsCaseInsensitiveEqual(ch, unshiftCh)) { continue;
}
// On the Hebrew keyboard layout on Windows, the unshifted char is a // localized character but the shifted char is a Latin alphabet, // then, we should not execute without the shift state. See bug 433192. if (IsCaseChangeableChar(ch)) { continue;
}
// Setting the alternative charCode candidates for retry without shift // key state only when the shift key is pressed.
ShortcutKeyCandidate key(ch, ShiftState::Ignorable,
SkipIfEarlierHandlerDisabled::No);
aCandidates.AppendElement(key);
}
}
// Special case for "Space" key. With some keyboard layouts, "Space" with // or without Shift key causes non-ASCII space. For such keyboard layouts, // we should guarantee that the key press works as an ASCII white space key // press. However, if the space key is assigned to a function key, it // shouldn't work as a space key. if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING &&
mCodeNameIndex == CODE_NAME_INDEX_Space && pseudoCharCode != ' ') {
ShortcutKeyCandidate spaceKey(' ', ShiftState::MatchExactly,
SkipIfEarlierHandlerDisabled::No);
aCandidates.AppendElement(spaceKey);
}
}
void WidgetKeyboardEvent::GetAccessKeyCandidates(
nsTArray<uint32_t>& aCandidates) const {
MOZ_ASSERT(aCandidates.IsEmpty(), "aCandidates must be empty");
// return the lower cased charCode candidates for access keys. // the priority of the charCodes are: // 0: charCode, 1: unshiftedCharCodes[0], 2: shiftedCharCodes[0] // 3: unshiftedCharCodes[1], 4: shiftedCharCodes[1],...
uint32_t pseudoCharCode = PseudoCharCode(); if (pseudoCharCode) {
uint32_t ch = pseudoCharCode; if (IS_IN_BMP(ch)) {
ch = ToLowerCase(static_cast<char16_t>(ch));
}
aCandidates.AppendElement(ch);
} for (uint32_t i = 0; i < mAlternativeCharCodes.Length(); ++i) {
uint32_t ch[2] = {mAlternativeCharCodes[i].mUnshiftedCharCode,
mAlternativeCharCodes[i].mShiftedCharCode}; for (uint32_t j = 0; j < 2; ++j) { if (!ch[j]) { continue;
} if (IS_IN_BMP(ch[j])) {
ch[j] = ToLowerCase(static_cast<char16_t>(ch[j]));
} // Don't append the charcode that was already appended. if (aCandidates.IndexOf(ch[j]) == aCandidates.NoIndex) {
aCandidates.AppendElement(ch[j]);
}
}
} // Special case for "Space" key. With some keyboard layouts, "Space" with // or without Shift key causes non-ASCII space. For such keyboard layouts, // we should guarantee that the key press works as an ASCII white space key // press. However, if the space key is assigned to a function key, it // shouldn't work as a space key. if (mKeyNameIndex == KEY_NAME_INDEX_USE_STRING &&
mCodeNameIndex == CODE_NAME_INDEX_Space && pseudoCharCode != ' ') {
aCandidates.AppendElement(' ');
}
}
// mask values for ui.key.chromeAccess and ui.key.contentAccess #define NS_MODIFIER_SHIFT 1 #define NS_MODIFIER_CONTROL 2 #define NS_MODIFIER_ALT 4 #define NS_MODIFIER_META 8
static Modifiers PrefFlagsToModifiers(int32_t aPrefFlags) {
Modifiers result = 0; if (aPrefFlags & NS_MODIFIER_SHIFT) {
result |= MODIFIER_SHIFT;
} if (aPrefFlags & NS_MODIFIER_CONTROL) {
result |= MODIFIER_CONTROL;
} if (aPrefFlags & NS_MODIFIER_ALT) {
result |= MODIFIER_ALT;
} if (aPrefFlags & NS_MODIFIER_META) {
result |= MODIFIER_META;
} return result;
}
/* static */
Modifiers WidgetKeyboardEvent::AccessKeyModifiers(AccessKeyType aType) { switch (StaticPrefs::ui_key_generalAccessKey()) { case -1: break; // use the individual prefs case NS_VK_SHIFT: return MODIFIER_SHIFT; case NS_VK_CONTROL: return MODIFIER_CONTROL; case NS_VK_ALT: return MODIFIER_ALT; case NS_VK_META: case NS_VK_WIN: return MODIFIER_META; default: return MODIFIER_NONE;
}
switch (aType) { case AccessKeyType::eChrome: return PrefFlagsToModifiers(StaticPrefs::ui_key_chromeAccess()); case AccessKeyType::eContent: return PrefFlagsToModifiers(StaticPrefs::ui_key_contentAccess()); default: return MODIFIER_NONE;
}
}
/* static */ void WidgetKeyboardEvent::Shutdown() { delete sKeyNameIndexHashtable;
sKeyNameIndexHashtable = nullptr; delete sCodeNameIndexHashtable;
sCodeNameIndexHashtable = nullptr; // Although sCommandHashtable is not a member of WidgetKeyboardEvent, but // let's delete it here since we need to do it at same time. delete sCommandHashtable;
sCommandHashtable = nullptr;
}
// Generate some continuous runs of codes, rather than looking them up. if (aCodeNameIndex >= CODE_NAME_INDEX_KeyA &&
aCodeNameIndex <= CODE_NAME_INDEX_KeyZ) {
uint32_t index = aCodeNameIndex - CODE_NAME_INDEX_KeyA;
aCodeName.AssignLiteral(u"Key");
aCodeName.Append(u'A' + index); return;
} if (aCodeNameIndex >= CODE_NAME_INDEX_Digit0 &&
aCodeNameIndex <= CODE_NAME_INDEX_Digit9) {
uint32_t index = aCodeNameIndex - CODE_NAME_INDEX_Digit0;
aCodeName.AssignLiteral(u"Digit");
aCodeName.AppendInt(index); return;
} if (aCodeNameIndex >= CODE_NAME_INDEX_Numpad0 &&
aCodeNameIndex <= CODE_NAME_INDEX_Numpad9) {
uint32_t index = aCodeNameIndex - CODE_NAME_INDEX_Numpad0;
aCodeName.AssignLiteral(u"Numpad");
aCodeName.AppendInt(index); return;
} if (aCodeNameIndex >= CODE_NAME_INDEX_F1 &&
aCodeNameIndex <= CODE_NAME_INDEX_F24) {
uint32_t index = aCodeNameIndex - CODE_NAME_INDEX_F1;
aCodeName.Assign(u'F');
aCodeName.AppendInt(index + 1); return;
}
aCodeName = kCodeNames[aCodeNameIndex];
}
/* static */
KeyNameIndex WidgetKeyboardEvent::GetKeyNameIndex(const nsAString& aKeyValue) { if (!sKeyNameIndexHashtable) {
sKeyNameIndexHashtable = new KeyNameIndexHashtable(std::size(kKeyNames)); for (size_t i = 0; i < std::size(kKeyNames); i++) {
sKeyNameIndexHashtable->InsertOrUpdate(nsDependentString(kKeyNames[i]), static_cast<KeyNameIndex>(i));
}
} return sKeyNameIndexHashtable->MaybeGet(aKeyValue).valueOr(
KEY_NAME_INDEX_USE_STRING);
}
/* static */
CodeNameIndex WidgetKeyboardEvent::GetCodeNameIndex( const nsAString& aCodeValue) { if (!sCodeNameIndexHashtable) {
sCodeNameIndexHashtable = new CodeNameIndexHashtable(std::size(kCodeNames)); for (size_t i = 0; i < std::size(kCodeNames); i++) {
sCodeNameIndexHashtable->InsertOrUpdate(nsDependentString(kCodeNames[i]), static_cast<CodeNameIndex>(i));
}
} return sCodeNameIndexHashtable->MaybeGet(aCodeValue)
.valueOr(CODE_NAME_INDEX_USE_STRING);
}
/* static */
uint32_t WidgetKeyboardEvent::GetFallbackKeyCodeOfPunctuationKey(
CodeNameIndex aCodeNameIndex) { switch (aCodeNameIndex) { case CODE_NAME_INDEX_Semicolon: // VK_OEM_1 on Windows return dom::KeyboardEvent_Binding::DOM_VK_SEMICOLON; case CODE_NAME_INDEX_Equal: // VK_OEM_PLUS on Windows return dom::KeyboardEvent_Binding::DOM_VK_EQUALS; case CODE_NAME_INDEX_Comma: // VK_OEM_COMMA on Windows return dom::KeyboardEvent_Binding::DOM_VK_COMMA; case CODE_NAME_INDEX_Minus: // VK_OEM_MINUS on Windows return dom::KeyboardEvent_Binding::DOM_VK_HYPHEN_MINUS; case CODE_NAME_INDEX_Period: // VK_OEM_PERIOD on Windows return dom::KeyboardEvent_Binding::DOM_VK_PERIOD; case CODE_NAME_INDEX_Slash: // VK_OEM_2 on Windows return dom::KeyboardEvent_Binding::DOM_VK_SLASH; case CODE_NAME_INDEX_Backquote: // VK_OEM_3 on Windows return dom::KeyboardEvent_Binding::DOM_VK_BACK_QUOTE; case CODE_NAME_INDEX_BracketLeft: // VK_OEM_4 on Windows return dom::KeyboardEvent_Binding::DOM_VK_OPEN_BRACKET; case CODE_NAME_INDEX_Backslash: // VK_OEM_5 on Windows return dom::KeyboardEvent_Binding::DOM_VK_BACK_SLASH; case CODE_NAME_INDEX_BracketRight: // VK_OEM_6 on Windows return dom::KeyboardEvent_Binding::DOM_VK_CLOSE_BRACKET; case CODE_NAME_INDEX_Quote: // VK_OEM_7 on Windows return dom::KeyboardEvent_Binding::DOM_VK_QUOTE; case CODE_NAME_INDEX_IntlBackslash: // VK_OEM_5 on Windows (ABNT, etc) case CODE_NAME_INDEX_IntlYen: // VK_OEM_5 on Windows (JIS) case CODE_NAME_INDEX_IntlRo: // VK_OEM_102 on Windows return dom::KeyboardEvent_Binding::DOM_VK_BACK_SLASH; default: return 0;
}
}
/* static */
uint32_t WidgetKeyboardEvent::ComputeLocationFromCodeValue(
CodeNameIndex aCodeNameIndex) { // Following commented out cases are not defined in PhysicalKeyCodeNameList.h // but are defined by D3E spec. So, they should be uncommented when the // code values are defined in the header. switch (aCodeNameIndex) { case CODE_NAME_INDEX_AltLeft: case CODE_NAME_INDEX_ControlLeft: case CODE_NAME_INDEX_MetaLeft: case CODE_NAME_INDEX_ShiftLeft: return eKeyLocationLeft; case CODE_NAME_INDEX_AltRight: case CODE_NAME_INDEX_ControlRight: case CODE_NAME_INDEX_MetaRight: case CODE_NAME_INDEX_ShiftRight: return eKeyLocationRight; case CODE_NAME_INDEX_Numpad0: case CODE_NAME_INDEX_Numpad1: case CODE_NAME_INDEX_Numpad2: case CODE_NAME_INDEX_Numpad3: case CODE_NAME_INDEX_Numpad4: case CODE_NAME_INDEX_Numpad5: case CODE_NAME_INDEX_Numpad6: case CODE_NAME_INDEX_Numpad7: case CODE_NAME_INDEX_Numpad8: case CODE_NAME_INDEX_Numpad9: case CODE_NAME_INDEX_NumpadAdd: case CODE_NAME_INDEX_NumpadBackspace: case CODE_NAME_INDEX_NumpadClear: case CODE_NAME_INDEX_NumpadClearEntry: case CODE_NAME_INDEX_NumpadComma: case CODE_NAME_INDEX_NumpadDecimal: case CODE_NAME_INDEX_NumpadDivide: case CODE_NAME_INDEX_NumpadEnter: case CODE_NAME_INDEX_NumpadEqual: case CODE_NAME_INDEX_NumpadMemoryAdd: case CODE_NAME_INDEX_NumpadMemoryClear: case CODE_NAME_INDEX_NumpadMemoryRecall: case CODE_NAME_INDEX_NumpadMemoryStore: case CODE_NAME_INDEX_NumpadMemorySubtract: case CODE_NAME_INDEX_NumpadMultiply: case CODE_NAME_INDEX_NumpadParenLeft: case CODE_NAME_INDEX_NumpadParenRight: case CODE_NAME_INDEX_NumpadSubtract: return eKeyLocationNumpad; default: return eKeyLocationStandard;
}
}
/* static */
uint32_t WidgetKeyboardEvent::ComputeKeyCodeFromKeyNameIndex(
KeyNameIndex aKeyNameIndex) { switch (aKeyNameIndex) { case KEY_NAME_INDEX_Cancel: return dom::KeyboardEvent_Binding::DOM_VK_CANCEL; case KEY_NAME_INDEX_Help: return dom::KeyboardEvent_Binding::DOM_VK_HELP; case KEY_NAME_INDEX_Backspace: return dom::KeyboardEvent_Binding::DOM_VK_BACK_SPACE; case KEY_NAME_INDEX_Tab: return dom::KeyboardEvent_Binding::DOM_VK_TAB; case KEY_NAME_INDEX_Clear: return dom::KeyboardEvent_Binding::DOM_VK_CLEAR; case KEY_NAME_INDEX_Enter: return dom::KeyboardEvent_Binding::DOM_VK_RETURN; case KEY_NAME_INDEX_Shift: return dom::KeyboardEvent_Binding::DOM_VK_SHIFT; case KEY_NAME_INDEX_Control: return dom::KeyboardEvent_Binding::DOM_VK_CONTROL; case KEY_NAME_INDEX_Alt: return dom::KeyboardEvent_Binding::DOM_VK_ALT; case KEY_NAME_INDEX_Pause: return dom::KeyboardEvent_Binding::DOM_VK_PAUSE; case KEY_NAME_INDEX_CapsLock: return dom::KeyboardEvent_Binding::DOM_VK_CAPS_LOCK; case KEY_NAME_INDEX_Hiragana: case KEY_NAME_INDEX_Katakana: case KEY_NAME_INDEX_HiraganaKatakana: case KEY_NAME_INDEX_KanaMode: return dom::KeyboardEvent_Binding::DOM_VK_KANA; case KEY_NAME_INDEX_HangulMode: return dom::KeyboardEvent_Binding::DOM_VK_HANGUL; case KEY_NAME_INDEX_Eisu: return dom::KeyboardEvent_Binding::DOM_VK_EISU; case KEY_NAME_INDEX_JunjaMode: return dom::KeyboardEvent_Binding::DOM_VK_JUNJA; case KEY_NAME_INDEX_FinalMode: return dom::KeyboardEvent_Binding::DOM_VK_FINAL; case KEY_NAME_INDEX_HanjaMode: return dom::KeyboardEvent_Binding::DOM_VK_HANJA; case KEY_NAME_INDEX_KanjiMode: return dom::KeyboardEvent_Binding::DOM_VK_KANJI; case KEY_NAME_INDEX_Escape: return dom::KeyboardEvent_Binding::DOM_VK_ESCAPE; case KEY_NAME_INDEX_Convert: return dom::KeyboardEvent_Binding::DOM_VK_CONVERT; case KEY_NAME_INDEX_NonConvert: return dom::KeyboardEvent_Binding::DOM_VK_NONCONVERT; case KEY_NAME_INDEX_Accept: return dom::KeyboardEvent_Binding::DOM_VK_ACCEPT; case KEY_NAME_INDEX_ModeChange: return dom::KeyboardEvent_Binding::DOM_VK_MODECHANGE; case KEY_NAME_INDEX_PageUp: return dom::KeyboardEvent_Binding::DOM_VK_PAGE_UP; case KEY_NAME_INDEX_PageDown: return dom::KeyboardEvent_Binding::DOM_VK_PAGE_DOWN; case KEY_NAME_INDEX_End: return dom::KeyboardEvent_Binding::DOM_VK_END; case KEY_NAME_INDEX_Home: return dom::KeyboardEvent_Binding::DOM_VK_HOME; case KEY_NAME_INDEX_ArrowLeft: return dom::KeyboardEvent_Binding::DOM_VK_LEFT; case KEY_NAME_INDEX_ArrowUp: return dom::KeyboardEvent_Binding::DOM_VK_UP; case KEY_NAME_INDEX_ArrowRight: return dom::KeyboardEvent_Binding::DOM_VK_RIGHT; case KEY_NAME_INDEX_ArrowDown: return dom::KeyboardEvent_Binding::DOM_VK_DOWN; case KEY_NAME_INDEX_Select: return dom::KeyboardEvent_Binding::DOM_VK_SELECT; case KEY_NAME_INDEX_Print: return dom::KeyboardEvent_Binding::DOM_VK_PRINT; case KEY_NAME_INDEX_Execute: return dom::KeyboardEvent_Binding::DOM_VK_EXECUTE; case KEY_NAME_INDEX_PrintScreen: return dom::KeyboardEvent_Binding::DOM_VK_PRINTSCREEN; case KEY_NAME_INDEX_Insert: return dom::KeyboardEvent_Binding::DOM_VK_INSERT; case KEY_NAME_INDEX_Delete: return dom::KeyboardEvent_Binding::DOM_VK_DELETE; case KEY_NAME_INDEX_ContextMenu: return dom::KeyboardEvent_Binding::DOM_VK_CONTEXT_MENU; case KEY_NAME_INDEX_Standby: return dom::KeyboardEvent_Binding::DOM_VK_SLEEP; case KEY_NAME_INDEX_F1: return dom::KeyboardEvent_Binding::DOM_VK_F1; case KEY_NAME_INDEX_F2: return dom::KeyboardEvent_Binding::DOM_VK_F2; case KEY_NAME_INDEX_F3: return dom::KeyboardEvent_Binding::DOM_VK_F3; case KEY_NAME_INDEX_F4: return dom::KeyboardEvent_Binding::DOM_VK_F4; case KEY_NAME_INDEX_F5: return dom::KeyboardEvent_Binding::DOM_VK_F5; case KEY_NAME_INDEX_F6: return dom::KeyboardEvent_Binding::DOM_VK_F6; case KEY_NAME_INDEX_F7: return dom::KeyboardEvent_Binding::DOM_VK_F7; case KEY_NAME_INDEX_F8: return dom::KeyboardEvent_Binding::DOM_VK_F8; case KEY_NAME_INDEX_F9: return dom::KeyboardEvent_Binding::DOM_VK_F9; case KEY_NAME_INDEX_F10: return dom::KeyboardEvent_Binding::DOM_VK_F10; case KEY_NAME_INDEX_F11: return dom::KeyboardEvent_Binding::DOM_VK_F11; case KEY_NAME_INDEX_F12: return dom::KeyboardEvent_Binding::DOM_VK_F12; case KEY_NAME_INDEX_F13: return dom::KeyboardEvent_Binding::DOM_VK_F13; case KEY_NAME_INDEX_F14: return dom::KeyboardEvent_Binding::DOM_VK_F14; case KEY_NAME_INDEX_F15: return dom::KeyboardEvent_Binding::DOM_VK_F15; case KEY_NAME_INDEX_F16: return dom::KeyboardEvent_Binding::DOM_VK_F16; case KEY_NAME_INDEX_F17: return dom::KeyboardEvent_Binding::DOM_VK_F17; case KEY_NAME_INDEX_F18: return dom::KeyboardEvent_Binding::DOM_VK_F18; case KEY_NAME_INDEX_F19: return dom::KeyboardEvent_Binding::DOM_VK_F19; case KEY_NAME_INDEX_F20: return dom::KeyboardEvent_Binding::DOM_VK_F20; case KEY_NAME_INDEX_F21: return dom::KeyboardEvent_Binding::DOM_VK_F21; case KEY_NAME_INDEX_F22: return dom::KeyboardEvent_Binding::DOM_VK_F22; case KEY_NAME_INDEX_F23: return dom::KeyboardEvent_Binding::DOM_VK_F23; case KEY_NAME_INDEX_F24: return dom::KeyboardEvent_Binding::DOM_VK_F24; case KEY_NAME_INDEX_NumLock: return dom::KeyboardEvent_Binding::DOM_VK_NUM_LOCK; case KEY_NAME_INDEX_ScrollLock: return dom::KeyboardEvent_Binding::DOM_VK_SCROLL_LOCK; case KEY_NAME_INDEX_AudioVolumeMute: return dom::KeyboardEvent_Binding::DOM_VK_VOLUME_MUTE; case KEY_NAME_INDEX_AudioVolumeDown: return dom::KeyboardEvent_Binding::DOM_VK_VOLUME_DOWN; case KEY_NAME_INDEX_AudioVolumeUp: return dom::KeyboardEvent_Binding::DOM_VK_VOLUME_UP; case KEY_NAME_INDEX_Meta: #ifdefined(XP_WIN) || defined(MOZ_WIDGET_GTK) return dom::KeyboardEvent_Binding::DOM_VK_WIN; #else return dom::KeyboardEvent_Binding::DOM_VK_META; #endif case KEY_NAME_INDEX_AltGraph: return dom::KeyboardEvent_Binding::DOM_VK_ALTGR; case KEY_NAME_INDEX_Process: return dom::KeyboardEvent_Binding::DOM_VK_PROCESSKEY; case KEY_NAME_INDEX_Attn: return dom::KeyboardEvent_Binding::DOM_VK_ATTN; case KEY_NAME_INDEX_CrSel: return dom::KeyboardEvent_Binding::DOM_VK_CRSEL; case KEY_NAME_INDEX_ExSel: return dom::KeyboardEvent_Binding::DOM_VK_EXSEL; case KEY_NAME_INDEX_EraseEof: return dom::KeyboardEvent_Binding::DOM_VK_EREOF; case KEY_NAME_INDEX_Play: return dom::KeyboardEvent_Binding::DOM_VK_PLAY; case KEY_NAME_INDEX_ZoomToggle: case KEY_NAME_INDEX_ZoomIn: case KEY_NAME_INDEX_ZoomOut: return dom::KeyboardEvent_Binding::DOM_VK_ZOOM; default: return 0;
}
}
/* static */
CodeNameIndex WidgetKeyboardEvent::ComputeCodeNameIndexFromKeyNameIndex(
KeyNameIndex aKeyNameIndex, const Maybe<uint32_t>& aLocation) { if (aLocation.isSome() &&
aLocation.value() ==
dom::KeyboardEvent_Binding::DOM_KEY_LOCATION_NUMPAD) { // On macOS, NumLock is not supported. Therefore, this handles // control key values except "Enter" only on non-macOS platforms. switch (aKeyNameIndex) { #ifndef XP_MACOSX case KEY_NAME_INDEX_Insert: return CODE_NAME_INDEX_Numpad0; case KEY_NAME_INDEX_End: return CODE_NAME_INDEX_Numpad1; case KEY_NAME_INDEX_ArrowDown: return CODE_NAME_INDEX_Numpad2; case KEY_NAME_INDEX_PageDown: return CODE_NAME_INDEX_Numpad3; case KEY_NAME_INDEX_ArrowLeft: return CODE_NAME_INDEX_Numpad4; case KEY_NAME_INDEX_Clear: // FYI: "Clear" on macOS should be DOM_KEY_LOCATION_STANDARD. return CODE_NAME_INDEX_Numpad5; case KEY_NAME_INDEX_ArrowRight: return CODE_NAME_INDEX_Numpad6; case KEY_NAME_INDEX_Home: return CODE_NAME_INDEX_Numpad7; case KEY_NAME_INDEX_ArrowUp: return CODE_NAME_INDEX_Numpad8; case KEY_NAME_INDEX_PageUp: return CODE_NAME_INDEX_Numpad9; case KEY_NAME_INDEX_Delete: return CODE_NAME_INDEX_NumpadDecimal; #endif// #ifndef XP_MACOSX case KEY_NAME_INDEX_Enter: return CODE_NAME_INDEX_NumpadEnter; default: return CODE_NAME_INDEX_UNKNOWN;
}
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.42Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.