зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1520983 - part 1: Add new content command event for inserting text r=smaug
For inserting text from OS in special cases, e.g., when inserting 2 or more characters per keydown or inserting text without key press, we use a set of composition events on macOS, but the other browsers don't use composition events. Instead, they expose only `beforeinput` event and `input` event. We should follow their behavior for web-compat because `beforeinput` events for IME composition are never cancelable, but the `beforeinput` events for the cases are cancelable of the other browsers. Differential Revision: https://phabricator.services.mozilla.com/D114826
This commit is contained in:
Родитель
7820e16a1d
Коммит
1bb2df9ea3
|
@ -2003,6 +2003,25 @@ nsDOMWindowUtils::GetIMEStatus(uint32_t* aState) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::GetInputContextOrigin(uint32_t* aOrigin) {
|
||||
NS_ENSURE_ARG_POINTER(aOrigin);
|
||||
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
InputContext context = widget->GetInputContext();
|
||||
static_assert(InputContext::Origin::ORIGIN_MAIN == INPUT_CONTEXT_ORIGIN_MAIN);
|
||||
static_assert(InputContext::Origin::ORIGIN_CONTENT ==
|
||||
INPUT_CONTEXT_ORIGIN_CONTENT);
|
||||
MOZ_ASSERT(context.mOrigin == InputContext::Origin::ORIGIN_MAIN ||
|
||||
context.mOrigin == InputContext::Origin::ORIGIN_CONTENT);
|
||||
*aOrigin = static_cast<uint32_t>(context.mOrigin);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::GetFocusedInputType(nsAString& aType) {
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
|
@ -2337,7 +2356,8 @@ nsDOMWindowUtils::SendSelectionSetEvent(uint32_t aOffset, uint32_t aLength,
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SendContentCommandEvent(const nsAString& aType,
|
||||
nsITransferable* aTransferable) {
|
||||
nsITransferable* aTransferable,
|
||||
const nsAString& aString) {
|
||||
// get the widget to send the event to
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget) return NS_ERROR_FAILURE;
|
||||
|
@ -2355,6 +2375,8 @@ nsDOMWindowUtils::SendContentCommandEvent(const nsAString& aType,
|
|||
msg = eContentCommandUndo;
|
||||
} else if (aType.EqualsLiteral("redo")) {
|
||||
msg = eContentCommandRedo;
|
||||
} else if (aType.EqualsLiteral("insertText")) {
|
||||
msg = eContentCommandInsertText;
|
||||
} else if (aType.EqualsLiteral("pasteTransferable")) {
|
||||
msg = eContentCommandPasteTransferable;
|
||||
} else {
|
||||
|
@ -2362,6 +2384,9 @@ nsDOMWindowUtils::SendContentCommandEvent(const nsAString& aType,
|
|||
}
|
||||
|
||||
WidgetContentCommandEvent event(true, msg, widget);
|
||||
if (msg == eContentCommandInsertText) {
|
||||
event.mString.emplace(aString);
|
||||
}
|
||||
if (msg == eContentCommandPasteTransferable) {
|
||||
event.mTransferable = aTransferable;
|
||||
}
|
||||
|
|
|
@ -875,6 +875,9 @@ nsresult EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
|||
case eContentCommandLookUpDictionary:
|
||||
DoContentCommandEvent(aEvent->AsContentCommandEvent());
|
||||
break;
|
||||
case eContentCommandInsertText:
|
||||
DoContentCommandInsertTextEvent(aEvent->AsContentCommandEvent());
|
||||
break;
|
||||
case eContentCommandScroll:
|
||||
DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
|
||||
break;
|
||||
|
@ -5923,6 +5926,43 @@ nsresult EventStateManager::DoContentCommandEvent(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult EventStateManager::DoContentCommandInsertTextEvent(
|
||||
WidgetContentCommandEvent* aEvent) {
|
||||
MOZ_ASSERT(aEvent);
|
||||
MOZ_ASSERT(aEvent->mMessage == eContentCommandInsertText);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aEvent->mString.isSome());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!aEvent->mString.ref().IsEmpty());
|
||||
|
||||
aEvent->mIsEnabled = false;
|
||||
aEvent->mSucceeded = false;
|
||||
|
||||
NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
// Handle it in focused content process if there is.
|
||||
if (BrowserParent* remote = BrowserParent::GetFocused()) {
|
||||
remote->SendInsertText(aEvent->mString.ref());
|
||||
aEvent->mIsEnabled = true; // XXX it can be a lie...
|
||||
aEvent->mSucceeded = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no active editor in this process, we should treat the command
|
||||
// is disabled.
|
||||
RefPtr<TextEditor> activeEditor =
|
||||
nsContentUtils::GetActiveEditor(mPresContext);
|
||||
if (!activeEditor) {
|
||||
aEvent->mSucceeded = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = activeEditor->InsertTextAsAction(aEvent->mString.ref());
|
||||
aEvent->mIsEnabled = rv != NS_SUCCESS_DOM_NO_OPERATION;
|
||||
aEvent->mSucceeded = NS_SUCCEEDED(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult EventStateManager::DoContentCommandScrollEvent(
|
||||
WidgetContentCommandEvent* aEvent) {
|
||||
NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE);
|
||||
|
|
|
@ -1039,6 +1039,8 @@ class EventStateManager : public nsSupportsWeakReference, public nsIObserver {
|
|||
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
nsresult DoContentCommandEvent(WidgetContentCommandEvent* aEvent);
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
nsresult DoContentCommandInsertTextEvent(WidgetContentCommandEvent* aEvent);
|
||||
nsresult DoContentCommandScrollEvent(WidgetContentCommandEvent* aEvent);
|
||||
|
||||
dom::BrowserParent* GetCrossProcessTarget();
|
||||
|
|
|
@ -1089,6 +1089,14 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||
*/
|
||||
readonly attribute unsigned long IMEStatus;
|
||||
|
||||
/**
|
||||
* Get whether current input context (including IME status) in the widget
|
||||
* is set by content or not.
|
||||
*/
|
||||
const unsigned long INPUT_CONTEXT_ORIGIN_MAIN = 0;
|
||||
const unsigned long INPUT_CONTEXT_ORIGIN_CONTENT = 1;
|
||||
readonly attribute unsigned long inputContextOrigin;
|
||||
|
||||
/**
|
||||
* Get the number of screen pixels per CSS pixel.
|
||||
*
|
||||
|
@ -1156,12 +1164,16 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||
* Will throw a DOM security error if called without chrome privileges.
|
||||
*
|
||||
* @param aType Type of command content event to send. Can be one of "cut",
|
||||
* "copy", "paste", "delete", "undo", "redo", or "pasteTransferable".
|
||||
* "copy", "paste", "delete", "undo", "redo", "insertText" or
|
||||
* "pasteTransferable".
|
||||
* @param aTransferable an instance of nsITransferable when aType is
|
||||
* "pasteTransferable"
|
||||
* @param aString The string to be inserted into focused editor when aType is
|
||||
* "insertText"
|
||||
*/
|
||||
void sendContentCommandEvent(in AString aType,
|
||||
[optional] in nsITransferable aTransferable);
|
||||
[optional] in nsITransferable aTransferable,
|
||||
[optional] in AString aString);
|
||||
|
||||
/**
|
||||
* If sendQueryContentEvent()'s aAdditionalFlags argument is
|
||||
|
|
|
@ -2105,6 +2105,21 @@ mozilla::ipc::IPCResult BrowserChild::RecvNormalPrioritySelectionEvent(
|
|||
return RecvSelectionEvent(aEvent);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserChild::RecvInsertText(
|
||||
const nsString& aStringToInsert) {
|
||||
// Use normal event path to reach focused document.
|
||||
WidgetContentCommandEvent localEvent(true, eContentCommandInsertText,
|
||||
mPuppetWidget);
|
||||
localEvent.mString = Some(aStringToInsert);
|
||||
DispatchWidgetEventViaAPZ(localEvent);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserChild::RecvNormalPriorityInsertText(
|
||||
const nsString& aStringToInsert) {
|
||||
return RecvInsertText(aStringToInsert);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserChild::RecvPasteTransferable(
|
||||
const IPCDataTransfer& aDataTransfer, const bool& aIsPrivateData,
|
||||
nsIPrincipal* aRequestingPrincipal,
|
||||
|
|
|
@ -417,6 +417,11 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
|||
mozilla::ipc::IPCResult RecvSetIsUnderHiddenEmbedderElement(
|
||||
const bool& aIsUnderHiddenEmbedderElement);
|
||||
|
||||
mozilla::ipc::IPCResult RecvInsertText(const nsString& aStringToInsert);
|
||||
|
||||
mozilla::ipc::IPCResult RecvNormalPriorityInsertText(
|
||||
const nsString& aStringToInsert);
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
mozilla::ipc::IPCResult RecvPasteTransferable(
|
||||
const IPCDataTransfer& aDataTransfer, const bool& aIsPrivateData,
|
||||
|
|
|
@ -3072,6 +3072,15 @@ bool BrowserParent::SendSelectionEvent(WidgetSelectionEvent& aEvent) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BrowserParent::SendInsertText(const nsString& aStringToInsert) {
|
||||
if (mIsDestroyed) {
|
||||
return false;
|
||||
}
|
||||
return Manager()->IsInputPriorityEventEnabled()
|
||||
? PBrowserParent::SendInsertText(aStringToInsert)
|
||||
: PBrowserParent::SendNormalPriorityInsertText(aStringToInsert);
|
||||
}
|
||||
|
||||
bool BrowserParent::SendPasteTransferable(
|
||||
const IPCDataTransfer& aDataTransfer, const bool& aIsPrivateData,
|
||||
nsIPrincipal* aRequestingPrincipal,
|
||||
|
|
|
@ -608,6 +608,8 @@ class BrowserParent final : public PBrowserParent,
|
|||
|
||||
bool HandleQueryContentEvent(mozilla::WidgetQueryContentEvent& aEvent);
|
||||
|
||||
bool SendInsertText(const nsString& aStringToInsert);
|
||||
|
||||
bool SendPasteTransferable(const IPCDataTransfer& aDataTransfer,
|
||||
const bool& aIsPrivateData,
|
||||
nsIPrincipal* aRequestingPrincipal,
|
||||
|
|
|
@ -869,6 +869,12 @@ child:
|
|||
[Priority=input] async SelectionEvent(WidgetSelectionEvent event);
|
||||
async NormalPrioritySelectionEvent(WidgetSelectionEvent event);
|
||||
|
||||
/**
|
||||
* Dispatch eContentCommandInsertText event in the remote process.
|
||||
*/
|
||||
[Priority=input] async InsertText(nsString aStringToInsert);
|
||||
async NormalPriorityInsertText(nsString aStringToInsert);
|
||||
|
||||
/**
|
||||
* Call PasteTransferable via a controller on the content process
|
||||
* to handle the command content event, "pasteTransferable".
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[browser_bug527935.js]
|
||||
skip-if = toolkit == 'android'
|
||||
prefs =
|
||||
editor.white_space_normalization.blink_compatible=true
|
||||
support-files =
|
||||
bug527935.html
|
||||
bug527935_2.html
|
||||
[browser_content_command_insert_text.js]
|
||||
|
|
|
@ -0,0 +1,271 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { CustomizableUITestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/CustomizableUITestUtils.jsm"
|
||||
);
|
||||
const { ContentTaskUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/ContentTaskUtils.jsm"
|
||||
);
|
||||
const gCUITestUtils = new CustomizableUITestUtils(window);
|
||||
const gDOMWindowUtils = EventUtils._getDOMWindowUtils(window);
|
||||
|
||||
add_task(async function test_setup() {
|
||||
await gCUITestUtils.addSearchBar();
|
||||
registerCleanupFunction(() => {
|
||||
gCUITestUtils.removeSearchBar();
|
||||
});
|
||||
});
|
||||
|
||||
function promiseResettingSearchBarAndFocus() {
|
||||
const waitForFocusInSearchBar = BrowserTestUtils.waitForEvent(
|
||||
BrowserSearch.searchBar.textbox,
|
||||
"focus"
|
||||
);
|
||||
BrowserSearch.searchBar.textbox.focus();
|
||||
BrowserSearch.searchBar.textbox.value = "";
|
||||
return Promise.all([
|
||||
waitForFocusInSearchBar,
|
||||
TestUtils.waitForCondition(
|
||||
() =>
|
||||
gDOMWindowUtils.IMEStatus === Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED &&
|
||||
gDOMWindowUtils.inputContextOrigin ===
|
||||
Ci.nsIDOMWindowUtils.INPUT_CONTEXT_ORIGIN_MAIN
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
function promiseIMEStateEnabledByRemote() {
|
||||
return TestUtils.waitForCondition(
|
||||
() =>
|
||||
gDOMWindowUtils.IMEStatus === Ci.nsIDOMWindowUtils.IME_STATUS_ENABLED &&
|
||||
gDOMWindowUtils.inputContextOrigin ===
|
||||
Ci.nsIDOMWindowUtils.INPUT_CONTEXT_ORIGIN_CONTENT
|
||||
);
|
||||
}
|
||||
|
||||
function promiseContentTick(browser) {
|
||||
return SpecialPowers.spawn(browser, [], async () => {
|
||||
await new Promise(r => {
|
||||
content.requestAnimationFrame(() => {
|
||||
content.requestAnimationFrame(r);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function test_text_editor_in_chrome() {
|
||||
await promiseResettingSearchBarAndFocus();
|
||||
|
||||
let events = [];
|
||||
function logEvent(event) {
|
||||
events.push(event);
|
||||
}
|
||||
BrowserSearch.searchBar.textbox.addEventListener("beforeinput", logEvent);
|
||||
gDOMWindowUtils.sendContentCommandEvent("insertText", null, "XYZ");
|
||||
|
||||
is(
|
||||
BrowserSearch.searchBar.textbox.value,
|
||||
"XYZ",
|
||||
"The string should be inserted into the focused search bar"
|
||||
);
|
||||
is(
|
||||
events.length,
|
||||
1,
|
||||
"One beforeinput event should be fired in the searchbar"
|
||||
);
|
||||
is(events[0]?.inputType, "insertText", 'inputType should be "insertText"');
|
||||
is(events[0]?.data, "XYZ", 'inputType should be "XYZ"');
|
||||
is(events[0]?.cancelable, true, "beforeinput event should be cancelable");
|
||||
BrowserSearch.searchBar.textbox.removeEventListener("beforeinput", logEvent);
|
||||
|
||||
BrowserSearch.searchBar.textbox.blur();
|
||||
});
|
||||
|
||||
add_task(async function test_text_editor_in_content() {
|
||||
for (const test of [
|
||||
{
|
||||
tag: "input",
|
||||
target: "input",
|
||||
nonTarget: "input + input",
|
||||
page: 'data:text/html,<input value="abc"><input value="def">',
|
||||
},
|
||||
{
|
||||
tag: "textarea",
|
||||
target: "textarea",
|
||||
nonTarget: "textarea + textarea",
|
||||
page: "data:text/html,<textarea>abc</textarea><textarea>def</textarea>",
|
||||
},
|
||||
]) {
|
||||
// Once, move focus to chrome's searchbar.
|
||||
await promiseResettingSearchBarAndFocus();
|
||||
|
||||
await BrowserTestUtils.withNewTab(test.page, async browser => {
|
||||
await SpecialPowers.spawn(browser, [test], async function(aTest) {
|
||||
content.window.focus();
|
||||
await ContentTaskUtils.waitForCondition(() =>
|
||||
content.document.hasFocus()
|
||||
);
|
||||
const target = content.document.querySelector(aTest.target);
|
||||
target.focus();
|
||||
target.selectionStart = target.selectionEnd = 2;
|
||||
content.document.documentElement.scrollTop; // Flush pending things
|
||||
});
|
||||
|
||||
await promiseIMEStateEnabledByRemote();
|
||||
const waitForBeforeInputEvent = SpecialPowers.spawn(
|
||||
browser,
|
||||
[test],
|
||||
async function(aTest) {
|
||||
await new Promise(resolve => {
|
||||
content.document.querySelector(aTest.target).addEventListener(
|
||||
"beforeinput",
|
||||
event => {
|
||||
is(
|
||||
event.inputType,
|
||||
"insertText",
|
||||
`The inputType of beforeinput event fired on <${aTest.target}> should be "insertText"`
|
||||
);
|
||||
is(
|
||||
event.data,
|
||||
"XYZ",
|
||||
`The data of beforeinput event fired on <${aTest.target}> should be "XYZ"`
|
||||
);
|
||||
is(
|
||||
event.cancelable,
|
||||
true,
|
||||
`The beforeinput event fired on <${aTest.target}> should be cancelable`
|
||||
);
|
||||
resolve();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
const waitForInputEvent = BrowserTestUtils.waitForContentEvent(
|
||||
browser,
|
||||
"input"
|
||||
);
|
||||
await promiseContentTick(browser); // Ensure "input" event listener in the remote process
|
||||
gDOMWindowUtils.sendContentCommandEvent("insertText", null, "XYZ");
|
||||
await waitForBeforeInputEvent;
|
||||
await waitForInputEvent;
|
||||
|
||||
await SpecialPowers.spawn(browser, [test], async function(aTest) {
|
||||
is(
|
||||
content.document.querySelector(aTest.target).value,
|
||||
"abXYZc",
|
||||
`The string should be inserted into the focused <${aTest.target}> element`
|
||||
);
|
||||
is(
|
||||
content.document.querySelector(aTest.nonTarget).value,
|
||||
"def",
|
||||
`The string should not be inserted into the non-focused <${aTest.nonTarget}> element`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
is(
|
||||
BrowserSearch.searchBar.textbox.value,
|
||||
"",
|
||||
"The string should not be inserted into the previously focused search bar"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function test_html_editor_in_content() {
|
||||
for (const test of [
|
||||
{
|
||||
mode: "contenteditable",
|
||||
target: "div",
|
||||
page: "data:text/html,<div contenteditable>abc</div>",
|
||||
},
|
||||
{
|
||||
mode: "designMode",
|
||||
target: "div",
|
||||
page: "data:text/html,<div>abc</div>",
|
||||
},
|
||||
]) {
|
||||
// Once, move focus to chrome's searchbar.
|
||||
await promiseResettingSearchBarAndFocus();
|
||||
|
||||
await BrowserTestUtils.withNewTab(test.page, async browser => {
|
||||
await SpecialPowers.spawn(browser, [test], async function(aTest) {
|
||||
content.window.focus();
|
||||
await ContentTaskUtils.waitForCondition(() =>
|
||||
content.document.hasFocus()
|
||||
);
|
||||
const target = content.document.querySelector(aTest.target);
|
||||
if (aTest.mode == "designMode") {
|
||||
content.document.designMode = "on";
|
||||
content.window.focus();
|
||||
} else {
|
||||
target.focus();
|
||||
}
|
||||
content.window.getSelection().collapse(target.firstChild, 2);
|
||||
content.document.documentElement.scrollTop; // Flush pending things
|
||||
});
|
||||
|
||||
await promiseIMEStateEnabledByRemote();
|
||||
const waitForBeforeInputEvent = SpecialPowers.spawn(
|
||||
browser,
|
||||
[test],
|
||||
async function(aTest) {
|
||||
await new Promise(resolve => {
|
||||
const eventTarget =
|
||||
aTest.mode === "designMode"
|
||||
? content.document
|
||||
: content.document.querySelector(aTest.target);
|
||||
eventTarget.addEventListener(
|
||||
"beforeinput",
|
||||
event => {
|
||||
is(
|
||||
event.inputType,
|
||||
"insertText",
|
||||
`The inputType of beforeinput event fired on ${aTest.mode} editor should be "insertText"`
|
||||
);
|
||||
is(
|
||||
event.data,
|
||||
"XYZ",
|
||||
`The data of beforeinput event fired on ${aTest.mode} editor should be "XYZ"`
|
||||
);
|
||||
is(
|
||||
event.cancelable,
|
||||
true,
|
||||
`The beforeinput event fired on ${aTest.mode} editor should be cancelable`
|
||||
);
|
||||
resolve();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
const waitForInputEvent = BrowserTestUtils.waitForContentEvent(
|
||||
browser,
|
||||
"input"
|
||||
);
|
||||
await promiseContentTick(browser); // Ensure "input" event listener in the remote process
|
||||
gDOMWindowUtils.sendContentCommandEvent("insertText", null, "XYZ");
|
||||
await waitForBeforeInputEvent;
|
||||
await waitForInputEvent;
|
||||
|
||||
await SpecialPowers.spawn(browser, [test], async function(aTest) {
|
||||
is(
|
||||
content.document.querySelector(aTest.target).innerHTML,
|
||||
"abXYZc",
|
||||
`The string should be inserted into the focused ${aTest.mode} editor`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
is(
|
||||
BrowserSearch.searchBar.textbox.value,
|
||||
"",
|
||||
"The string should not be inserted into the previously focused search bar"
|
||||
);
|
||||
}
|
||||
});
|
|
@ -327,6 +327,9 @@ NS_EVENT_MESSAGE(eContentCommandPaste)
|
|||
NS_EVENT_MESSAGE(eContentCommandDelete)
|
||||
NS_EVENT_MESSAGE(eContentCommandUndo)
|
||||
NS_EVENT_MESSAGE(eContentCommandRedo)
|
||||
// eContentCommandInsertText tries to insert text with replacing selection
|
||||
// in focused editor.
|
||||
NS_EVENT_MESSAGE(eContentCommandInsertText)
|
||||
NS_EVENT_MESSAGE(eContentCommandPasteTransferable)
|
||||
NS_EVENT_MESSAGE(eContentCommandLookUpDictionary)
|
||||
// eContentCommandScroll scrolls the nearest scrollable element to the
|
||||
|
|
|
@ -9,10 +9,12 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "mozilla/BasicEvents.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAtom.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsITransferable.h"
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -47,6 +49,9 @@ class WidgetContentCommandEvent : public WidgetGUIEvent {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// eContentCommandInsertText
|
||||
mozilla::Maybe<nsString> mString; // [in]
|
||||
|
||||
// eContentCommandPasteTransferable
|
||||
nsCOMPtr<nsITransferable> mTransferable; // [in]
|
||||
|
||||
|
@ -72,6 +77,7 @@ class WidgetContentCommandEvent : public WidgetGUIEvent {
|
|||
bool aCopyTargets) {
|
||||
AssignGUIEventData(aEvent, aCopyTargets);
|
||||
|
||||
mString = aEvent.mString;
|
||||
mScroll = aEvent.mScroll;
|
||||
mOnlyEnabledCheck = aEvent.mOnlyEnabledCheck;
|
||||
mSucceeded = aEvent.mSucceeded;
|
||||
|
|
Загрузка…
Ссылка в новой задаче