diff --git a/dom/html/nsTextEditorState.cpp b/dom/html/nsTextEditorState.cpp index 3023994f2575..479a6b534fd0 100644 --- a/dom/html/nsTextEditorState.cpp +++ b/dom/html/nsTextEditorState.cpp @@ -45,6 +45,9 @@ #include "nsFrameSelection.h" #include "mozilla/ErrorResult.h" #include "mozilla/Telemetry.h" +#include "mozilla/ShortcutKeys.h" +#include "nsXBLPrototypeHandler.h" +#include "mozilla/dom/KeyboardEvent.h" using namespace mozilla; using namespace mozilla::dom; @@ -957,13 +960,44 @@ TextInputListener::HandleEvent(Event* aEvent) return NS_OK; } - WidgetKeyboardEvent* keyEvent = - aEvent->WidgetEventPtr()->AsKeyboardEvent(); + RefPtr keyEvent = aEvent->AsKeyboardEvent(); if (!keyEvent) { return NS_ERROR_UNEXPECTED; } - if (keyEvent->mMessage != eKeyPress) { + WidgetKeyboardEvent* widgetKeyEvent = + aEvent->WidgetEventPtr()->AsKeyboardEvent(); + if (!keyEvent) { + return NS_ERROR_UNEXPECTED; + } + + nsXBLPrototypeHandler* keyHandlers = + ShortcutKeys::GetHandlers(mTxtCtrlElement->IsTextArea() ? + HandlerType::eTextArea : HandlerType::eInput); + + RefPtr eventTypeAtom = + ShortcutKeys::ConvertEventToDOMEventType(widgetKeyEvent); + for (nsXBLPrototypeHandler* handler = keyHandlers; + handler; + handler = handler->GetNextHandler()) { + if (!handler->EventTypeEquals(eventTypeAtom)) { + continue; + } + + if (!handler->KeyEventMatched(keyEvent, 0, IgnoreModifierState())) { + continue; + } + + // XXX Do we execute only one handler even if the handler neither stops + // propagation nor prevents default of the event? + nsCOMPtr target = do_QueryInterface(mTxtCtrlElement); + nsresult rv = handler->ExecuteHandler(target, aEvent); + if (NS_SUCCEEDED(rv)) { + return rv; + } + } + + if (widgetKeyEvent->mMessage != eKeyPress) { return NS_OK; } @@ -972,7 +1006,7 @@ TextInputListener::HandleEvent(Event* aEvent) nsIWidget::NativeKeyBindingsForMultiLineEditor : nsIWidget::NativeKeyBindingsForSingleLineEditor; - nsIWidget* widget = keyEvent->mWidget; + nsIWidget* widget = widgetKeyEvent->mWidget; // If the event is created by chrome script, the widget is nullptr. if (!widget) { widget = mFrame->GetNearestWidget(); @@ -983,10 +1017,10 @@ TextInputListener::HandleEvent(Event* aEvent) // If the event is created by chrome script, it is nullptr but we need to // execute native key bindings. Therefore, we need to set widget to // WidgetEvent::mWidget temporarily. - AutoRestore> saveWidget(keyEvent->mWidget); - keyEvent->mWidget = widget; - if (keyEvent->ExecuteEditCommands(nativeKeyBindingsType, - DoCommandCallback, mFrame)) { + AutoRestore> saveWidget(widgetKeyEvent->mWidget); + widgetKeyEvent->mWidget = widget; + if (widgetKeyEvent->ExecuteEditCommands(nativeKeyBindingsType, + DoCommandCallback, mFrame)) { aEvent->PreventDefault(); } return NS_OK; diff --git a/dom/xbl/builtin/ShortcutKeys.cpp b/dom/xbl/builtin/ShortcutKeys.cpp index 15fc2cfdcb15..138e1d0dd614 100644 --- a/dom/xbl/builtin/ShortcutKeys.cpp +++ b/dom/xbl/builtin/ShortcutKeys.cpp @@ -1,6 +1,8 @@ #include "mozilla/ShortcutKeys.h" #include "../nsXBLPrototypeHandler.h" #include "nsContentUtils.h" +#include "nsAtom.h" +#include "mozilla/TextEvents.h" namespace mozilla { @@ -44,6 +46,28 @@ ShortcutKeys::GetHandlers(HandlerType aType) return sInstance->EnsureHandlers(aType); } +/* static */ nsAtom* +ShortcutKeys::ConvertEventToDOMEventType(const WidgetKeyboardEvent* aWidgetKeyboardEvent) +{ + if (aWidgetKeyboardEvent->IsKeyDownOrKeyDownOnPlugin()) { + return nsGkAtoms::keydown; + } + if (aWidgetKeyboardEvent->IsKeyUpOrKeyUpOnPlugin()) { + return nsGkAtoms::keyup; + } + // eAccessKeyNotFound event is always created from eKeyPress event and + // the original eKeyPress event has stopped its propagation before dispatched + // into the DOM tree in this process and not matched with remote content's + // access keys. So, we should treat it as an eKeyPress event and execute + // a command if it's registered as a shortcut key. + if (aWidgetKeyboardEvent->mMessage == eKeyPress || + aWidgetKeyboardEvent->mMessage == eAccessKeyNotFound) { + return nsGkAtoms::keypress; + } + MOZ_ASSERT_UNREACHABLE("All event messages relating to shortcut keys should be handled"); + return nullptr; +} + nsXBLPrototypeHandler* ShortcutKeys::EnsureHandlers(HandlerType aType) { diff --git a/dom/xbl/builtin/ShortcutKeys.h b/dom/xbl/builtin/ShortcutKeys.h index 263cc3b5ff5b..a7bdc88f1923 100644 --- a/dom/xbl/builtin/ShortcutKeys.h +++ b/dom/xbl/builtin/ShortcutKeys.h @@ -8,9 +8,12 @@ #include "nsIObserver.h" class nsXBLPrototypeHandler; +class nsAtom; namespace mozilla { +class WidgetKeyboardEvent; + typedef struct { const char16_t* event; @@ -37,6 +40,9 @@ public: // Returns a pointer to the first handler for the given type. static nsXBLPrototypeHandler* GetHandlers(HandlerType aType); + // Gets the event type for a widget keyboard event. + static nsAtom* ConvertEventToDOMEventType(const WidgetKeyboardEvent* aWidgetKeyboardEvent); + protected: ShortcutKeys(); virtual ~ShortcutKeys(); diff --git a/dom/xbl/moz.build b/dom/xbl/moz.build index a58842f902f7..07c9f4ee26d3 100644 --- a/dom/xbl/moz.build +++ b/dom/xbl/moz.build @@ -12,6 +12,7 @@ DIRS += ['builtin'] EXPORTS += [ 'nsBindingManager.h', 'nsXBLBinding.h', + 'nsXBLPrototypeHandler.h', 'nsXBLService.h', 'nsXBLWindowKeyHandler.h', ] diff --git a/dom/xbl/nsXBLWindowKeyHandler.cpp b/dom/xbl/nsXBLWindowKeyHandler.cpp index 78bb17fd9b07..794a3af4a13f 100644 --- a/dom/xbl/nsXBLWindowKeyHandler.cpp +++ b/dom/xbl/nsXBLWindowKeyHandler.cpp @@ -137,7 +137,7 @@ nsXBLWindowKeyHandler::EnsureHandlers() } nsresult -nsXBLWindowKeyHandler::WalkHandlers(KeyboardEvent* aKeyEvent, nsAtom* aEventType) +nsXBLWindowKeyHandler::WalkHandlers(KeyboardEvent* aKeyEvent) { if (aKeyEvent->DefaultPrevented()) { return NS_OK; @@ -159,7 +159,7 @@ nsXBLWindowKeyHandler::WalkHandlers(KeyboardEvent* aKeyEvent, nsAtom* aEventType return NS_OK; } - WalkHandlersInternal(aKeyEvent, aEventType, true); + WalkHandlersInternal(aKeyEvent, true); return NS_OK; } @@ -309,30 +309,6 @@ nsXBLWindowKeyHandler::CollectKeyboardShortcuts() return KeyboardMap(std::move(shortcuts)); } -nsAtom* -nsXBLWindowKeyHandler::ConvertEventToDOMEventType( - const WidgetKeyboardEvent& aWidgetKeyboardEvent) const -{ - if (aWidgetKeyboardEvent.IsKeyDownOrKeyDownOnPlugin()) { - return nsGkAtoms::keydown; - } - if (aWidgetKeyboardEvent.IsKeyUpOrKeyUpOnPlugin()) { - return nsGkAtoms::keyup; - } - // eAccessKeyNotFound event is always created from eKeyPress event and - // the original eKeyPress event has stopped its propagation before dispatched - // into the DOM tree in this process and not matched with remote content's - // access keys. So, we should treat it as an eKeyPress event and execute - // a command if it's registered as a shortcut key. - if (aWidgetKeyboardEvent.mMessage == eKeyPress || - aWidgetKeyboardEvent.mMessage == eAccessKeyNotFound) { - return nsGkAtoms::keypress; - } - MOZ_ASSERT_UNREACHABLE( - "All event messages which this instance listens to should be handled"); - return nullptr; -} - NS_IMETHODIMP nsXBLWindowKeyHandler::HandleEvent(Event* aEvent) { @@ -380,9 +356,7 @@ nsXBLWindowKeyHandler::HandleEvent(Event* aEvent) return NS_OK; } - RefPtr eventTypeAtom = - ConvertEventToDOMEventType(*widgetKeyboardEvent); - return WalkHandlers(keyEvent, eventTypeAtom); + return WalkHandlers(keyEvent); } void @@ -490,7 +464,6 @@ nsXBLWindowKeyHandler::IsHTMLEditableFieldFocused() // bool nsXBLWindowKeyHandler::WalkHandlersInternal(KeyboardEvent* aKeyEvent, - nsAtom* aEventType, bool aExecute, bool* aOutReservedForChrome) { @@ -502,8 +475,7 @@ nsXBLWindowKeyHandler::WalkHandlersInternal(KeyboardEvent* aKeyEvent, nativeKeyboardEvent->GetShortcutKeyCandidates(shortcutKeys); if (shortcutKeys.IsEmpty()) { - return WalkHandlersAndExecute(aKeyEvent, aEventType, - 0, IgnoreModifierState(), + return WalkHandlersAndExecute(aKeyEvent, 0, IgnoreModifierState(), aExecute, aOutReservedForChrome); } @@ -511,8 +483,7 @@ nsXBLWindowKeyHandler::WalkHandlersInternal(KeyboardEvent* aKeyEvent, ShortcutKeyCandidate& key = shortcutKeys[i]; IgnoreModifierState ignoreModifierState; ignoreModifierState.mShift = key.mIgnoreShift; - if (WalkHandlersAndExecute(aKeyEvent, aEventType, - key.mCharCode, ignoreModifierState, + if (WalkHandlersAndExecute(aKeyEvent, key.mCharCode, ignoreModifierState, aExecute, aOutReservedForChrome)) { return true; } @@ -523,7 +494,6 @@ nsXBLWindowKeyHandler::WalkHandlersInternal(KeyboardEvent* aKeyEvent, bool nsXBLWindowKeyHandler::WalkHandlersAndExecute( KeyboardEvent* aKeyEvent, - nsAtom* aEventType, uint32_t aCharCode, const IgnoreModifierState& aIgnoreModifierState, bool aExecute, @@ -539,6 +509,8 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute( return false; } + nsAtom* eventType = ShortcutKeys::ConvertEventToDOMEventType(widgetKeyboardEvent); + // Try all of the handlers until we find one that matches the event. for (nsXBLPrototypeHandler* handler = mHandler; handler; @@ -560,7 +532,7 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute( } // The other event types should exactly be matched with the handler's // event type. - } else if (!handler->EventTypeEquals(aEventType)) { + } else if (!handler->EventTypeEquals(eventType)) { continue; } } else { @@ -571,12 +543,12 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute( // prevented, following keypress event won't be fired. However, if // following keypress event is reserved, we shouldn't allow web // contents to prevent the default of the preceding keydown event. - if (aEventType != nsGkAtoms::keydown && - aEventType != nsGkAtoms::keypress) { + if (eventType != nsGkAtoms::keydown && + eventType != nsGkAtoms::keypress) { continue; } - } else if (!handler->EventTypeEquals(aEventType)) { - // Otherwise, aEventType should exactly be matched. + } else if (!handler->EventTypeEquals(eventType)) { + // Otherwise, eventType should exactly be matched. continue; } } @@ -601,7 +573,7 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute( } if (!aExecute) { - if (handler->EventTypeEquals(aEventType)) { + if (handler->EventTypeEquals(eventType)) { if (aOutReservedForChrome) { *aOutReservedForChrome = IsReservedKey(widgetKeyboardEvent, handler); } @@ -612,7 +584,7 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute( // If the command is reserved and the event is keydown, check also if // the handler is for keypress because if following keypress event is // reserved, we shouldn't dispatch the event into web contents. - if (aEventType == nsGkAtoms::keydown && + if (eventType == nsGkAtoms::keydown && handler->EventTypeEquals(nsGkAtoms::keypress)) { if (IsReservedKey(widgetKeyboardEvent, handler)) { if (aOutReservedForChrome) { @@ -661,8 +633,8 @@ nsXBLWindowKeyHandler::WalkHandlersAndExecute( if (!aIgnoreModifierState.mOS && widgetKeyboardEvent->IsOS()) { IgnoreModifierState ignoreModifierState(aIgnoreModifierState); ignoreModifierState.mOS = true; - return WalkHandlersAndExecute(aKeyEvent, aEventType, - aCharCode, ignoreModifierState, aExecute); + return WalkHandlersAndExecute(aKeyEvent, aCharCode, ignoreModifierState, + aExecute); } #endif @@ -707,10 +679,7 @@ nsXBLWindowKeyHandler::HasHandlerForEvent(KeyboardEvent* aEvent, return false; } - RefPtr eventTypeAtom = - ConvertEventToDOMEventType(*widgetKeyboardEvent); - return WalkHandlersInternal(aEvent, eventTypeAtom, false, - aOutReservedForChrome); + return WalkHandlersInternal(aEvent, false, aOutReservedForChrome); } already_AddRefed diff --git a/dom/xbl/nsXBLWindowKeyHandler.h b/dom/xbl/nsXBLWindowKeyHandler.h index 135dd034ee58..f38b049f90ea 100644 --- a/dom/xbl/nsXBLWindowKeyHandler.h +++ b/dom/xbl/nsXBLWindowKeyHandler.h @@ -50,17 +50,16 @@ public: protected: virtual ~nsXBLWindowKeyHandler(); - nsresult WalkHandlers(KeyboardEvent* aKeyEvent, nsAtom* aEventType); + nsresult WalkHandlers(KeyboardEvent* aKeyEvent); // walk the handlers, looking for one to handle the event bool WalkHandlersInternal(KeyboardEvent* aKeyEvent, - nsAtom* aEventType, bool aExecute, bool* aOutReservedForChrome = nullptr); // walk the handlers for aEvent, aCharCode and aIgnoreModifierState. Execute // it if aExecute = true. - bool WalkHandlersAndExecute(KeyboardEvent* aKeyEvent, nsAtom* aEventType, + bool WalkHandlersAndExecute(KeyboardEvent* aKeyEvent, uint32_t aCharCode, const IgnoreModifierState& aIgnoreModifierState, bool aExecute, @@ -82,12 +81,6 @@ protected: bool IsReservedKey(mozilla::WidgetKeyboardEvent* aKeyEvent, nsXBLPrototypeHandler* aHandler); - // Returns event type for matching between aWidgetKeyboardEvent and - // shortcut key handlers. This is used for calling WalkHandlers(), - // WalkHandlersInternal() and WalkHandlersAndExecute(). - nsAtom* ConvertEventToDOMEventType( - const mozilla::WidgetKeyboardEvent& aWidgetKeyboardEvent) const; - // lazily load the handlers. Overridden to handle being attached // to a particular element rather than the document nsresult EnsureHandlers(); diff --git a/layout/style/res/forms.css b/layout/style/res/forms.css index 7b44e708415c..a49bec4971c3 100644 --- a/layout/style/res/forms.css +++ b/layout/style/res/forms.css @@ -102,7 +102,6 @@ input { word-spacing: normal; letter-spacing: normal; cursor: text; - -moz-binding: url("chrome://global/content/platformHTMLBindings.xml#inputFields"); text-indent: 0; -moz-user-select: text; text-shadow: none; @@ -134,7 +133,6 @@ textarea { vertical-align: text-bottom; cursor: text; resize: both; - -moz-binding: url("chrome://global/content/platformHTMLBindings.xml#textAreas"); -moz-appearance: textfield-multiline; text-indent: 0; -moz-user-select: text; @@ -448,7 +446,6 @@ input[type="hidden"] { border: 0; cursor: auto; -moz-user-focus: ignore; - -moz-binding: none; } /* image buttons */ @@ -460,7 +457,6 @@ input[type="image"] { font-family: sans-serif; font-size: small; cursor: pointer; - -moz-binding: none; } input[type="image"]:disabled { @@ -482,7 +478,6 @@ input[type="file"] { /* Revert rules which apply on all inputs. */ -moz-appearance: none; - -moz-binding: none; cursor: default; border: none; @@ -552,7 +547,6 @@ input[type="checkbox"] { cursor: default; /* unset some values from the general 'input' rule above: */ padding: unset; - -moz-binding: unset; border: unset; background-color: unset; color: unset; @@ -608,7 +602,6 @@ input[type="submit"] { cursor: default; box-sizing: border-box; -moz-user-select: none; - -moz-binding: none; } /* Text-related properties for buttons: these ones are not shared with @@ -893,7 +886,6 @@ input[type=range] { cursor: default; background: none; border: none; - -moz-binding: none; /* we don't want any of platformHTMLBindings.xml#inputFields */ /* Prevent nsFrame::HandlePress setting mouse capture to this element. */ -moz-user-select: none ! important; } @@ -1015,7 +1007,6 @@ input[type=range]::-moz-range-thumb { input[type="number"] { -moz-appearance: number-input; /* Has to revert some properties applied by the generic input rule. */ - -moz-binding: none; inline-size: 20ch; /* It'd be nice if this matched the default inline-size of , but that's not easy to achieve due to platform differences. */