mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-02 22:37:50 +00:00
Bug 1119609 part.4 Add keydown() and keyup() to nsITextInputProcessor r=smaug, sr=smaug
This commit is contained in:
parent
27d34fdbd2
commit
5ef7ce5e6c
@ -5,6 +5,7 @@
|
||||
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/TextEventDispatcher.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "mozilla/TextInputProcessor.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIWidget.h"
|
||||
@ -430,4 +431,119 @@ TextInputProcessor::OnRemovedFrom(TextEventDispatcher* aTextEventDispatcher)
|
||||
UnlinkFromTextEventDispatcher();
|
||||
}
|
||||
|
||||
nsresult
|
||||
TextInputProcessor::PrepareKeyboardEventToDispatch(
|
||||
WidgetKeyboardEvent& aKeyboardEvent,
|
||||
uint32_t aKeyFlags)
|
||||
{
|
||||
if (NS_WARN_IF(aKeyboardEvent.mCodeNameIndex == CODE_NAME_INDEX_USE_STRING)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
if ((aKeyFlags & KEY_NON_PRINTABLE_KEY) &&
|
||||
NS_WARN_IF(aKeyboardEvent.mKeyNameIndex == KEY_NAME_INDEX_USE_STRING)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
if ((aKeyFlags & KEY_FORCE_PRINTABLE_KEY) &&
|
||||
aKeyboardEvent.mKeyNameIndex != KEY_NAME_INDEX_USE_STRING) {
|
||||
aKeyboardEvent.GetDOMKeyName(aKeyboardEvent.mKeyValue);
|
||||
aKeyboardEvent.mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TextInputProcessor::Keydown(nsIDOMKeyEvent* aDOMKeyEvent,
|
||||
uint32_t aKeyFlags,
|
||||
uint8_t aOptionalArgc,
|
||||
bool* aDoDefault)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(aDoDefault, "aDoDefault must not be nullptr");
|
||||
MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
|
||||
if (!aOptionalArgc) {
|
||||
aKeyFlags = 0;
|
||||
}
|
||||
*aDoDefault = false;
|
||||
if (NS_WARN_IF(!aDOMKeyEvent)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
WidgetKeyboardEvent* originalKeyEvent =
|
||||
aDOMKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
|
||||
if (NS_WARN_IF(!originalKeyEvent)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
// We shouldn't modify the internal WidgetKeyboardEvent.
|
||||
WidgetKeyboardEvent keyEvent(*originalKeyEvent);
|
||||
nsresult rv = PrepareKeyboardEventToDispatch(keyEvent, aKeyFlags);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
*aDoDefault = !(aKeyFlags & KEY_DEFAULT_PREVENTED);
|
||||
// XXX Ignore specified modifier flags for now
|
||||
keyEvent.modifiers = MODIFIER_NONE;
|
||||
|
||||
nsRefPtr<TextEventDispatcher> kungfuDeathGrip(mDispatcher);
|
||||
rv = IsValidStateForComposition();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsEventStatus status = *aDoDefault ? nsEventStatus_eIgnore :
|
||||
nsEventStatus_eConsumeNoDefault;
|
||||
if (!mDispatcher->DispatchKeyboardEvent(NS_KEY_DOWN, keyEvent, status)) {
|
||||
// If keydown event isn't dispatched, we don't need to dispatch keypress
|
||||
// events.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mDispatcher->MaybeDispatchKeypressEvents(keyEvent, status);
|
||||
|
||||
*aDoDefault = (status != nsEventStatus_eConsumeNoDefault);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TextInputProcessor::Keyup(nsIDOMKeyEvent* aDOMKeyEvent,
|
||||
uint32_t aKeyFlags,
|
||||
uint8_t aOptionalArgc,
|
||||
bool* aDoDefault)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(aDoDefault, "aDoDefault must not be nullptr");
|
||||
MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
|
||||
if (!aOptionalArgc) {
|
||||
aKeyFlags = 0;
|
||||
}
|
||||
*aDoDefault = false;
|
||||
if (NS_WARN_IF(!aDOMKeyEvent)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
WidgetKeyboardEvent* originalKeyEvent =
|
||||
aDOMKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
|
||||
if (NS_WARN_IF(!originalKeyEvent)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
// We shouldn't modify the internal WidgetKeyboardEvent.
|
||||
WidgetKeyboardEvent keyEvent(*originalKeyEvent);
|
||||
nsresult rv = PrepareKeyboardEventToDispatch(keyEvent, aKeyFlags);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
*aDoDefault = !(aKeyFlags & KEY_DEFAULT_PREVENTED);
|
||||
// XXX Ignore specified modifier flags for now
|
||||
keyEvent.modifiers = MODIFIER_NONE;
|
||||
|
||||
nsRefPtr<TextEventDispatcher> kungfuDeathGrip(mDispatcher);
|
||||
rv = IsValidStateForComposition();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsEventStatus status = *aDoDefault ? nsEventStatus_eIgnore :
|
||||
nsEventStatus_eConsumeNoDefault;
|
||||
mDispatcher->DispatchKeyboardEvent(NS_KEY_UP, keyEvent, status);
|
||||
*aDoDefault = (status != nsEventStatus_eConsumeNoDefault);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -48,6 +48,8 @@ private:
|
||||
nsresult CancelCompositionInternal();
|
||||
nsresult IsValidStateForComposition();
|
||||
void UnlinkFromTextEventDispatcher();
|
||||
nsresult PrepareKeyboardEventToDispatch(WidgetKeyboardEvent& aKeyboardEvent,
|
||||
uint32_t aKeyFlags);
|
||||
|
||||
TextEventDispatcher* mDispatcher; // [Weak]
|
||||
nsCOMPtr<nsITextInputProcessorCallback> mCallback;
|
||||
|
@ -219,6 +219,44 @@ function runBeginInputTransactionMethodTests()
|
||||
description + "The input element should not have commit string");
|
||||
}
|
||||
|
||||
// Let's check if keydown() throws an exception after ownership is stolen.
|
||||
ok(TIP1.beginInputTransactionForTests(window),
|
||||
description + "TIP1.beginInputTransactionForTests() should succeed because there is no composition");
|
||||
ok(TIP2.beginInputTransactionForTests(window),
|
||||
description + "TIP2.beginInputTransactionForTests() should succeed because there is no composition");
|
||||
input.value = "";
|
||||
try {
|
||||
var keyF = new KeyboardEvent("", { key: "f", code: "KeyF", keyCode: KeyboardEvent.DOM_VK_F });
|
||||
TIP1.keydown(keyF);
|
||||
ok(false,
|
||||
description + "TIP1.keydown(keyF) should cause throwing an exception because TIP2 took the ownership");
|
||||
} catch (e) {
|
||||
ok(e.message.contains("NS_ERROR_NOT_INITIALIZED"),
|
||||
description + "TIP1.keydown(keyF) should cause throwing an exception including NS_ERROR_NOT_INITIALIZED");
|
||||
} finally {
|
||||
is(input.value, "",
|
||||
description + "The input element should not be modified");
|
||||
}
|
||||
|
||||
// Let's check if keyup() throws an exception after ownership is stolen.
|
||||
ok(TIP1.beginInputTransactionForTests(window),
|
||||
description + "TIP1.beginInputTransactionForTests() should succeed because there is no composition");
|
||||
ok(TIP2.beginInputTransactionForTests(window),
|
||||
description + "TIP2.beginInputTransactionForTests() should succeed because there is no composition");
|
||||
input.value = "";
|
||||
try {
|
||||
var keyF = new KeyboardEvent("", { key: "f", code: "KeyF", keyCode: KeyboardEvent.DOM_VK_F });
|
||||
TIP1.keyup(keyF);
|
||||
ok(false,
|
||||
description + "TIP1.keyup(keyF) should cause throwing an exception because TIP2 took the ownership");
|
||||
} catch (e) {
|
||||
ok(e.message.contains("NS_ERROR_NOT_INITIALIZED"),
|
||||
description + "TIP1.keyup(keyF) should cause throwing an exception including NS_ERROR_NOT_INITIALIZED");
|
||||
} finally {
|
||||
is(input.value, "",
|
||||
description + "The input element should not be modified");
|
||||
}
|
||||
|
||||
// aCallback of nsITextInputProcessor.beginInputTransaction() must not be omitted.
|
||||
try {
|
||||
TIP1.beginInputTransaction(window);
|
||||
@ -525,6 +563,357 @@ function runCompositionTests()
|
||||
window.removeEventListener("compositionend", handler, false);
|
||||
}
|
||||
|
||||
function runKeyTests()
|
||||
{
|
||||
var description = "runKeyTests(): ";
|
||||
|
||||
var TIP = createTIP();
|
||||
ok(TIP.beginInputTransactionForTests(window),
|
||||
description + "TIP.beginInputTransactionForTests() should succeed");
|
||||
|
||||
var events;
|
||||
var doPreventDefaults;
|
||||
|
||||
function reset()
|
||||
{
|
||||
events = [];
|
||||
doPreventDefaults = [];
|
||||
}
|
||||
|
||||
function handler(aEvent)
|
||||
{
|
||||
events.push(aEvent);
|
||||
if (doPreventDefaults.indexOf(aEvent.type) >= 0) {
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
function checkKeyAttrs(aMethodDescription, aEvent, aExpectedData)
|
||||
{
|
||||
var desc = description + aMethodDescription + ", type=\"" + aEvent.type + "\", key=\"" + aEvent.key + "\", code=\"" + aEvent.code + "\": ";
|
||||
var defaultValues = {
|
||||
key: "Unidentified", code: "", keyCode: 0, charCode: 0,
|
||||
location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD, repeat: false, isComposing: false,
|
||||
shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
|
||||
defaultPrevented: false
|
||||
};
|
||||
var modifiers = [
|
||||
"AltGraph", "CapsLock", "Fn", "NumLock", "OS", "ScrollLock", "Symbol"
|
||||
];
|
||||
function expectedValue(aAttr)
|
||||
{
|
||||
return aExpectedData[aAttr] !== undefined ? aExpectedData[aAttr] : defaultValues[aAttr];
|
||||
}
|
||||
is(aEvent.type, aExpectedData.type,
|
||||
desc + " should cause keydown event");
|
||||
if (aEvent.type != aExpectedData.type) {
|
||||
return;
|
||||
}
|
||||
is(aEvent.defaultPrevented, expectedValue("defaultPrevented"),
|
||||
desc + ".defaultPrevented is wrong");
|
||||
is(aEvent.key, expectedValue("key"),
|
||||
desc + ".key is wrong");
|
||||
if (SpecialPowers.getBoolPref("dom.keyboardevent.code.enabled")) {
|
||||
is(aEvent.code, expectedValue("code"),
|
||||
desc + ".code is wrong");
|
||||
}
|
||||
is(aEvent.location, expectedValue("location"),
|
||||
desc + ".location is wrong");
|
||||
is(aEvent.repeat, expectedValue("repeat"),
|
||||
desc + ".repeat is wrong");
|
||||
is(aEvent.isComposing, expectedValue("isComposing"),
|
||||
desc + ".isComposing is wrong");
|
||||
is(aEvent.keyCode, expectedValue("keyCode"),
|
||||
desc + ".keyCode is wrong");
|
||||
is(aEvent.charCode, expectedValue("charCode"),
|
||||
desc + ".charCode is wrong");
|
||||
is(aEvent.shiftKey, expectedValue("shiftKey"),
|
||||
desc + ".shiftKey is wrong");
|
||||
is(aEvent.ctrlKey, expectedValue("ctrlKey"),
|
||||
desc + ".ctrlKey is wrong");
|
||||
is(aEvent.altKey, expectedValue("altKey"),
|
||||
desc + ".altKey is wrong");
|
||||
is(aEvent.metaKey, expectedValue("metaKey"),
|
||||
desc + ".metaKey is wrong");
|
||||
for (var i = 0; i < modifiers.length; i++) {
|
||||
is(aEvent.getModifierState(modifiers[i]), aExpectedData[modifiers[i]] !== undefined ? aExpectedData[modifiers[i]] : false,
|
||||
desc + ".getModifierState(\"" + modifiers[i] + "\") is wrong");
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("keydown", handler, false);
|
||||
window.addEventListener("keypress", handler, false);
|
||||
window.addEventListener("keyup", handler, false);
|
||||
|
||||
input.value = "";
|
||||
input.focus();
|
||||
|
||||
|
||||
// Printable key test:
|
||||
// Emulates pressing 'a' key.
|
||||
var keyA = new KeyboardEvent("", { key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A });
|
||||
|
||||
reset();
|
||||
var doDefaultKeydown = TIP.keydown(keyA);
|
||||
|
||||
ok(!doDefaultKeydown,
|
||||
description + "TIP.keydown(keyA) should return false because the keypress event should be consumed by the input element");
|
||||
is(events.length, 2,
|
||||
description + "TIP.keydown(keyA) should cause keydown and keypress event");
|
||||
checkKeyAttrs("TIP.keydown(keyA)", events[0],
|
||||
{ type: "keydown", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0 });
|
||||
checkKeyAttrs("TIP.keydown(keyA)", events[1],
|
||||
{ type: "keypress", key: "a", code: "KeyA", keyCode: 0, charCode: "a".charCodeAt(0), defaultPrevented: true });
|
||||
is(input.value, "a",
|
||||
description + "input.value should be \"a\" which is inputted by TIP.keydown(keyA)");
|
||||
|
||||
// Emulates releasing 'a' key.
|
||||
reset();
|
||||
var doDefaultKeyup = TIP.keyup(keyA);
|
||||
ok(doDefaultKeyup,
|
||||
description + "TIP.keyup(keyA) should return true");
|
||||
is(events.length, 1,
|
||||
description + "TIP.keyup(keyA) should cause keyup event");
|
||||
checkKeyAttrs("TIP.keyup(keyA)", events[0],
|
||||
{ type: "keyup", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0 });
|
||||
is(input.value, "a",
|
||||
description + "input.value should stay \"a\" which was inputted by TIP.keydown(keyA)");
|
||||
|
||||
|
||||
// Non-printable key test:
|
||||
// Emulates pressing Enter key.
|
||||
var keyEnter = new KeyboardEvent("", { key: "Enter", code: "Enter" });
|
||||
|
||||
reset();
|
||||
doDefaultKeydown = TIP.keydown(keyEnter);
|
||||
|
||||
ok(doDefaultKeydown,
|
||||
description + "TIP.keydown(keyEnter) should return true");
|
||||
is(events.length, 2,
|
||||
description + "TIP.keydown(keyEnter) should cause keydown and keypress event");
|
||||
checkKeyAttrs("TIP.keydown(keyEnter)", events[0],
|
||||
{ type: "keydown", key: "Enter", code: "Enter" });
|
||||
checkKeyAttrs("TIP.keydown(keyEnter)", events[1],
|
||||
{ type: "keypress", key: "Enter", code: "Enter" });
|
||||
is(input.value, "a",
|
||||
description + "input.value should stay \"a\" which was inputted by TIP.keydown(keyA)");
|
||||
|
||||
// Emulates releasing Enter key.
|
||||
reset();
|
||||
doDefaultKeyup = TIP.keyup(keyEnter);
|
||||
ok(doDefaultKeyup,
|
||||
description + "TIP.keyup(keyEnter) should return true");
|
||||
is(events.length, 1,
|
||||
description + "TIP.keyup(keyEnter) should cause keyup event");
|
||||
checkKeyAttrs("TIP.keyup(keyEnter)", events[0],
|
||||
{ type: "keyup", key: "Enter", code: "Enter" });
|
||||
is(input.value, "a",
|
||||
description + "input.value should stay \"a\" which was inputted by TIP.keydown(keyA)");
|
||||
|
||||
|
||||
// KEY_DEFAULT_PREVENTED should cause defaultPrevented = true and not cause keypress event
|
||||
var keyB = new KeyboardEvent("", { key: "b", code: "KeyB", keyCode: KeyboardEvent.DOM_VK_B });
|
||||
|
||||
reset();
|
||||
doDefaultKeydown = TIP.keydown(keyB, TIP.KEY_DEFAULT_PREVENTED);
|
||||
doDefaultKeyup = TIP.keyup(keyB, TIP.KEY_DEFAULT_PREVENTED);
|
||||
|
||||
ok(!doDefaultKeydown,
|
||||
description + "TIP.keydown(keyB, TIP.KEY_DEFAULT_PREVENTED) should return false because it's marked as consumed at dispatching the event");
|
||||
ok(!doDefaultKeyup,
|
||||
description + "TIP.keyup(keyB, TIP.KEY_DEFAULT_PREVENTED) should return false because it's marked as consumed at dispatching the event");
|
||||
is(events.length, 2,
|
||||
description + "TIP.keydown(keyB, TIP.KEY_DEFAULT_PREVENTED) and TIP.keyup(keyB, TIP.KEY_DEFAULT_PREVENTED) should cause keydown and keyup event");
|
||||
checkKeyAttrs("TIP.keydown(keyB, TIP.KEY_DEFAULT_PREVENTED) and TIP.keyup(keyB, TIP.KEY_DEFAULT_PREVENTED)", events[0],
|
||||
{ type: "keydown", key: "b", code: "KeyB", keyCode: KeyboardEvent.DOM_VK_B, defaultPrevented: true });
|
||||
checkKeyAttrs("TIP.keydown(keyB, TIP.KEY_DEFAULT_PREVENTED) and TIP.keyup(keyB, TIP.KEY_DEFAULT_PREVENTED)", events[1],
|
||||
{ type: "keyup", key: "b", code: "KeyB", keyCode: KeyboardEvent.DOM_VK_B, defaultPrevented: true });
|
||||
is(input.value, "a",
|
||||
description + "input.value shouldn't be modified by default prevented key events");
|
||||
|
||||
// Assume that KeyX causes inputting text "abc"
|
||||
input.value = "";
|
||||
var keyABC = new KeyboardEvent("", { key: "abc", code: "KeyX", keyCode: KeyboardEvent.DOM_VK_A });
|
||||
|
||||
reset();
|
||||
doDefaultKeydown = TIP.keydown(keyABC);
|
||||
doDefaultKeyup = TIP.keyup(keyABC);
|
||||
|
||||
ok(!doDefaultKeydown,
|
||||
description + "TIP.keydown(keyABC) should return false because the keypress events should be consumed by the input element");
|
||||
ok(doDefaultKeyup,
|
||||
description + "TIP.keyup(keyABC) should return true");
|
||||
is(events.length, 5,
|
||||
description + "TIP.keydown(keyABC) and TIP.keyup(keyABC) should cause keydown, keypress, keypress, keypress and keyup event");
|
||||
checkKeyAttrs("TIP.keydown(keyABC) and TIP.keyup(keyABC)", events[0],
|
||||
{ type: "keydown", key: "abc", code: "KeyX", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0, defaultPrevented: false });
|
||||
checkKeyAttrs("TIP.keydown(keyABC) and TIP.keyup(keyABC)", events[1],
|
||||
{ type: "keypress", key: "abc".charAt(0), code: "KeyX", keyCode: 0, charCode: "abc".charCodeAt(0), defaultPrevented: true });
|
||||
checkKeyAttrs("TIP.keydown(keyABC) and TIP.keyup(keyABC)", events[2],
|
||||
{ type: "keypress", key: "abc".charAt(1), code: "KeyX", keyCode: 0, charCode: "abc".charCodeAt(1), defaultPrevented: true });
|
||||
checkKeyAttrs("TIP.keydown(keyABC) and TIP.keyup(keyABC)", events[3],
|
||||
{ type: "keypress", key: "abc".charAt(2), code: "KeyX", keyCode: 0, charCode: "abc".charCodeAt(2), defaultPrevented: true });
|
||||
checkKeyAttrs("TIP.keydown(keyABC) and TIP.keyup(keyABC)", events[4],
|
||||
{ type: "keyup", key: "abc", code: "KeyX", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0, defaultPrevented: false });
|
||||
is(input.value, "abc",
|
||||
description + "input.value should be \"abc\"");
|
||||
|
||||
// If KEY_FORCE_PRINTABLE_KEY is specified, registered key names can be a printable key which inputs the specified value.
|
||||
input.value = "";
|
||||
var keyEnterPrintable = new KeyboardEvent("", { key: "Enter", code: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN });
|
||||
|
||||
reset();
|
||||
doDefaultKeydown = TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY);
|
||||
doDefaultKeyup = TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY);
|
||||
|
||||
ok(!doDefaultKeydown,
|
||||
description + "TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) should return false because the keypress events should be consumed by the input element");
|
||||
ok(doDefaultKeyup,
|
||||
description + "TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) should return true");
|
||||
is(events.length, 7,
|
||||
description + "TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) and TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) should cause keydown, keypress, keypress, keypress, keypress, keypress and keyup event");
|
||||
checkKeyAttrs("TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) and TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY)", events[0],
|
||||
{ type: "keydown", key: "Enter", code: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN, charCode: 0, defaultPrevented: false });
|
||||
checkKeyAttrs("TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) and TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY)", events[1],
|
||||
{ type: "keypress", key: "Enter".charAt(0), code: "Enter", keyCode: 0, charCode: "Enter".charCodeAt(0), defaultPrevented: true });
|
||||
checkKeyAttrs("TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) and TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY)", events[2],
|
||||
{ type: "keypress", key: "Enter".charAt(1), code: "Enter", keyCode: 0, charCode: "Enter".charCodeAt(1), defaultPrevented: true });
|
||||
checkKeyAttrs("TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) and TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY)", events[3],
|
||||
{ type: "keypress", key: "Enter".charAt(2), code: "Enter", keyCode: 0, charCode: "Enter".charCodeAt(2), defaultPrevented: true });
|
||||
checkKeyAttrs("TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) and TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY)", events[4],
|
||||
{ type: "keypress", key: "Enter".charAt(3), code: "Enter", keyCode: 0, charCode: "Enter".charCodeAt(3), defaultPrevented: true });
|
||||
checkKeyAttrs("TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) and TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY)", events[5],
|
||||
{ type: "keypress", key: "Enter".charAt(4), code: "Enter", keyCode: 0, charCode: "Enter".charCodeAt(4), defaultPrevented: true });
|
||||
checkKeyAttrs("TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY) and TIP.keyup(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY)", events[6],
|
||||
{ type: "keyup", key: "Enter", code: "Enter", keyCode: KeyboardEvent.DOM_VK_RETURN, charCode: 0, defaultPrevented: false });
|
||||
is(input.value, "Enter",
|
||||
description + "input.value should be \"Enter\"");
|
||||
|
||||
// modifiers should be ignored.
|
||||
var keyWithModifiers = new KeyboardEvent("", { key: "Escape", code: "Escape", shiftKey: true, ctrlKey: true, altKey: true, metaKey: true });
|
||||
|
||||
reset();
|
||||
doDefaultKeydown = TIP.keydown(keyWithModifiers);
|
||||
doDefaultKeyup = TIP.keyup(keyWithModifiers);
|
||||
|
||||
ok(doDefaultKeydown,
|
||||
description + "TIP.keydown(keyWithModifiers) should return true");
|
||||
ok(doDefaultKeyup,
|
||||
description + "TIP.keyup(keyWithModifiers) should return true");
|
||||
is(events.length, 3,
|
||||
description + "TIP.keydown(keyWithModifiers) and TIP.keyup(keyWithModifiers) should cause keydown, keypress and keyup event");
|
||||
checkKeyAttrs("TIP.keydown(keyWithModifiers) and TIP.keyup(keyWithModifiers)", events[0],
|
||||
{ type: "keydown", key: "Escape", code: "Escape" });
|
||||
checkKeyAttrs("TIP.keydown(keyWithModifiers) and TIP.keyup(keyWithModifiers)", events[1],
|
||||
{ type: "keypress", key: "Escape", code: "Escape" });
|
||||
checkKeyAttrs("TIP.keydown(keyWithModifiers) and TIP.keyup(keyWithModifiers)", events[2],
|
||||
{ type: "keyup", key: "Escape", code: "Escape" });
|
||||
is(input.value, "Enter",
|
||||
description + "input.value should stay \"Enter\" which was inputted by TIP.keydown(keyEnterPrintable, TIP.KEY_FORCE_PRINTABLE_KEY)");
|
||||
|
||||
// Call preventDefault() at keydown
|
||||
input.value = "";
|
||||
reset();
|
||||
doPreventDefaults = [ "keydown" ];
|
||||
doDefaultKeydown = TIP.keydown(keyA);
|
||||
doDefaultKeyup = TIP.keyup(keyA);
|
||||
|
||||
ok(!doDefaultKeydown,
|
||||
description + "TIP.keydown(keyA) should return false because keydown event's preventDefault should be called");
|
||||
ok(doDefaultKeyup,
|
||||
description + "TIP.keyup(keyA) should return true");
|
||||
is(events.length, 2,
|
||||
description + "TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keydown should cause keydown and keyup event");
|
||||
checkKeyAttrs("TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keydown", events[0],
|
||||
{ type: "keydown", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, defaultPrevented: true });
|
||||
checkKeyAttrs("TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keydown", events[1],
|
||||
{ type: "keyup", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, defaultPrevented: false });
|
||||
is(input.value, "",
|
||||
description + "input.value shouldn't be modified by TIP.keyup(keyA) if the keydown event is consumed");
|
||||
|
||||
// Call preventDefault() at keypress
|
||||
reset();
|
||||
doPreventDefaults = [ "keypress" ];
|
||||
doDefaultKeydown = TIP.keydown(keyA);
|
||||
doDefaultKeyup = TIP.keyup(keyA);
|
||||
|
||||
ok(!doDefaultKeydown,
|
||||
description + "TIP.keydown(keyA) should return false because keypress event's preventDefault should be called");
|
||||
ok(doDefaultKeyup,
|
||||
description + "TIP.keyup(keyA) should return true");
|
||||
is(events.length, 3,
|
||||
description + "TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keypress should cause keydown, keypress and keyup event");
|
||||
checkKeyAttrs("TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keypress", events[0],
|
||||
{ type: "keydown", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0, defaultPrevented: false });
|
||||
checkKeyAttrs("TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keypress", events[1],
|
||||
{ type: "keypress", key: "a", code: "KeyA", keyCode: 0, charCode: "a".charCodeAt(0), defaultPrevented: true });
|
||||
checkKeyAttrs("TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keypress", events[2],
|
||||
{ type: "keyup", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0, defaultPrevented: false });
|
||||
is(input.value, "",
|
||||
description + "input.value shouldn't be modified by TIP.keyup(keyA) if the keypress event is consumed");
|
||||
|
||||
// Call preventDefault() at keyup
|
||||
input.value = "";
|
||||
reset();
|
||||
doPreventDefaults = [ "keyup" ];
|
||||
doDefaultKeydown = TIP.keydown(keyA);
|
||||
doDefaultKeyup = TIP.keyup(keyA);
|
||||
|
||||
ok(!doDefaultKeydown,
|
||||
description + "TIP.keydown(keyA) should return false because the key event should be consumed by the input element");
|
||||
ok(!doDefaultKeyup,
|
||||
description + "TIP.keyup(keyA) should return false because keyup event's preventDefault should be called");
|
||||
is(events.length, 3,
|
||||
description + "TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keyup should cause keydown, keypress and keyup event");
|
||||
checkKeyAttrs("TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keyup", events[0],
|
||||
{ type: "keydown", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0, defaultPrevented: false });
|
||||
checkKeyAttrs("TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keyup", events[1],
|
||||
{ type: "keypress", key: "a", code: "KeyA", keyCode: 0, charCode: "a".charCodeAt(0), defaultPrevented: true });
|
||||
checkKeyAttrs("TIP.keydown(keyA) and TIP.keyup(keyA) with preventing default of keyup", events[2],
|
||||
{ type: "keyup", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0, defaultPrevented: true });
|
||||
is(input.value, "a",
|
||||
description + "input.value should be \"a\" by TIP.keyup(keyA) even if the keyup event is consumed");
|
||||
|
||||
// key events during composition
|
||||
try {
|
||||
SpecialPowers.setBoolPref("dom.keyboardevent.dispatch_during_composition", false);
|
||||
|
||||
ok(TIP.startComposition(), "TIP.startComposition() should start composition");
|
||||
|
||||
input.value = "";
|
||||
reset();
|
||||
TIP.keydown(keyA);
|
||||
is(events.length, 0,
|
||||
description + "TIP.keydown(keyA) shouldn't cause key events during composition if it's disabled by the pref");
|
||||
reset();
|
||||
TIP.keyup(keyA);
|
||||
is(events.length, 0,
|
||||
description + "TIP.keyup(keyA) shouldn't cause key events during composition if it's disabled by the pref");
|
||||
|
||||
SpecialPowers.setBoolPref("dom.keyboardevent.dispatch_during_composition", true);
|
||||
reset();
|
||||
TIP.keydown(keyA);
|
||||
is(events.length, 1,
|
||||
description + "TIP.keydown(keyA) should cause keydown event even composition if it's enabled by the pref");
|
||||
checkKeyAttrs("TIP.keydown(keyA) during composition", events[0],
|
||||
{ type: "keydown", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0, isComposing: true });
|
||||
reset();
|
||||
TIP.keyup(keyA);
|
||||
is(events.length, 1,
|
||||
description + "TIP.keyup(keyA) should cause keyup event even composition if it's enabled by the pref");
|
||||
checkKeyAttrs("TIP.keyup(keyA) during composition", events[0],
|
||||
{ type: "keyup", key: "a", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A, charCode: 0, isComposing: true });
|
||||
|
||||
} finally {
|
||||
TIP.cancelComposition();
|
||||
SpecialPowers.clearUserPref("dom.keyboardevent.dispatch_during_composition");
|
||||
}
|
||||
|
||||
window.removeEventListener("keydown", handler, false);
|
||||
window.removeEventListener("keypress", handler, false);
|
||||
window.removeEventListener("keyup", handler, false);
|
||||
}
|
||||
|
||||
function runErrorTests()
|
||||
{
|
||||
var description = "runErrorTests(): ";
|
||||
@ -667,6 +1056,66 @@ function runErrorTests()
|
||||
ok(e.message.contains("NS_ERROR_ILLEGAL_VALUE"),
|
||||
description + "flushPendingComposition() should cause NS_ERROR_ILLEGAL_VALUE if caret position is out of composition string");
|
||||
}
|
||||
|
||||
// Calling keydown() with a KeyboardEvent initialized with invalid code value should cause an exception.
|
||||
input.value = "";
|
||||
try {
|
||||
var keyInvalidCode = new KeyboardEvent("", { key: "f", code: "InvalidCodeValue", keyCode: KeyboardEvent.DOM_VK_F });
|
||||
TIP.keydown(keyInvalidCode);
|
||||
ok(false,
|
||||
description + "TIP.keydown(keyInvalidCode) should cause throwing an exception because its code value is not registered");
|
||||
} catch (e) {
|
||||
ok(e.message.contains("NS_ERROR_ILLEGAL_VALUE"),
|
||||
description + "TIP.keydown(keyInvalidCode) should cause throwing an exception including NS_ERROR_ILLEGAL_VALUE");
|
||||
} finally {
|
||||
is(input.value, "",
|
||||
description + "The input element should not be modified");
|
||||
}
|
||||
|
||||
// Calling keyup() with a KeyboardEvent initialized with invalid code value should cause an exception.
|
||||
input.value = "";
|
||||
try {
|
||||
var keyInvalidCode = new KeyboardEvent("", { key: "f", code: "InvalidCodeValue", keyCode: KeyboardEvent.DOM_VK_F });
|
||||
TIP.keyup(keyInvalidCode);
|
||||
ok(false,
|
||||
description + "TIP.keyup(keyInvalidCode) should cause throwing an exception because its code value is not registered");
|
||||
} catch (e) {
|
||||
ok(e.message.contains("NS_ERROR_ILLEGAL_VALUE"),
|
||||
description + "TIP.keyup(keyInvalidCode) should cause throwing an exception including NS_ERROR_ILLEGAL_VALUE");
|
||||
} finally {
|
||||
is(input.value, "",
|
||||
description + "The input element should not be modified");
|
||||
}
|
||||
|
||||
// Calling keydown(KEY_NON_PRINTABLE_KEY) with a KeyboardEvent initialized with non-key name should cause an exception.
|
||||
input.value = "";
|
||||
try {
|
||||
var keyInvalidKey = new KeyboardEvent("", { key: "ESCAPE", code: "Escape", keyCode: KeyboardEvent.DOM_VK_Escape});
|
||||
TIP.keydown(keyInvalidKey, TIP.KEY_NON_PRINTABLE_KEY);
|
||||
ok(false,
|
||||
description + "TIP.keydown(keyInvalidKey, TIP.KEY_NON_PRINTABLE_KEY) should cause throwing an exception because its key value is not registered");
|
||||
} catch (e) {
|
||||
ok(e.message.contains("NS_ERROR_ILLEGAL_VALUE"),
|
||||
description + "keydown(keyInvalidKey, TIP.KEY_NON_PRINTABLE_KEY) should cause throwing an exception including NS_ERROR_ILLEGAL_VALUE");
|
||||
} finally {
|
||||
is(input.value, "",
|
||||
description + "The input element should not be modified");
|
||||
}
|
||||
|
||||
// Calling keyup(KEY_NON_PRINTABLE_KEY) with a KeyboardEvent initialized with non-key name should cause an exception.
|
||||
input.value = "";
|
||||
try {
|
||||
var keyInvalidKey = new KeyboardEvent("", { key: "ESCAPE", code: "Escape", keyCode: KeyboardEvent.DOM_VK_Escape});
|
||||
TIP.keydown(keyInvalidKey, TIP.KEY_NON_PRINTABLE_KEY);
|
||||
ok(false,
|
||||
description + "TIP.keyup(keyInvalidKey, TIP.KEY_NON_PRINTABLE_KEY) should cause throwing an exception because its key value is not registered");
|
||||
} catch (e) {
|
||||
ok(e.message.contains("NS_ERROR_ILLEGAL_VALUE"),
|
||||
description + "keyup(keyInvalidKey, TIP.KEY_NON_PRINTABLE_KEY) should cause throwing an exception including NS_ERROR_ILLEGAL_VALUE");
|
||||
} finally {
|
||||
is(input.value, "",
|
||||
description + "The input element should not be modified");
|
||||
}
|
||||
}
|
||||
|
||||
function runCommitCompositionTests()
|
||||
@ -1021,6 +1470,7 @@ function runTests()
|
||||
runBeginInputTransactionMethodTests();
|
||||
runReleaseTests();
|
||||
runCompositionTests();
|
||||
runKeyTests();
|
||||
runErrorTests();
|
||||
runCommitCompositionTests();
|
||||
runCallbackTests(false);
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMKeyEvent;
|
||||
interface nsIDOMWindow;
|
||||
interface nsITextInputProcessorCallback;
|
||||
|
||||
@ -103,9 +104,102 @@ interface nsITextInputProcessorCallback;
|
||||
* }
|
||||
* // And when user selects a result from UI of JS-IME, commit with it.
|
||||
* TIP.commitComposition("selected-words");
|
||||
*
|
||||
* Example #8 JS-IME or JS-Keyboard should dispatch key events even during
|
||||
* composition (non-printable key case):
|
||||
*
|
||||
* if (!TIP.beginInputTransaction(window, callback)) {
|
||||
* return; // You failed to get the rights to dispatch key events
|
||||
* }
|
||||
*
|
||||
* // You don't need to specify .keyCode value if it's non-printable key
|
||||
* // because it can be computed from .key value.
|
||||
* // If you specify non-zero value to .keyCode, it'll be used.
|
||||
* var keyEvent = new KeyboardEvent("", { code: "Enter", key: "Enter" });
|
||||
* if (TIP.keydown(keyEvent)) {
|
||||
* // Handle its default action
|
||||
* }
|
||||
*
|
||||
* // You should call beginInputTransaction() or
|
||||
* // beginInputTransactionForTests() before every keydow() or keyup() call
|
||||
* // because somebody stole the right to compose on the window. E.g., in
|
||||
* // this case, another TIP might start composition at receiving a DOM event
|
||||
* // which was caused by preceding keydown().
|
||||
* if (!TIP.beginInputTransaction(window, callback)) {
|
||||
* return; // You failed to get the rights to dispatch key events
|
||||
* }
|
||||
*
|
||||
* // Even if keydown event was consumed, keyup event should be dispatched.
|
||||
* if (TIP.keyup(keyEvent)) {
|
||||
* // Handle its default action
|
||||
* }
|
||||
*
|
||||
* Example #9 JS-IME or JS-Keyboard should dispatch key events even during
|
||||
* composition (printable key case):
|
||||
*
|
||||
* if (!TIP.beginInputTransaction(window, callback)) {
|
||||
* return; // You failed to get the rights to dispatch key events
|
||||
* }
|
||||
*
|
||||
* // You need to specify .keyCode value if it's printable key.
|
||||
* // The rules of .keyCode value is documented in MDN:
|
||||
* // https://developer.mozilla.org/docs/Web/API/KeyboardEvent.keyCode
|
||||
* //
|
||||
* // #1 If the key location is DOM_KEY_LOCATION_NUMPAD and NumLock is
|
||||
* // active, you should specify DOM_VK_NUMPAD[0-9], DOM_VK_MULTIPLY,
|
||||
* // DOM_VK_ADD, DOM_VK_SEPARATOR, DOM_VK_SUBTRACT, DOM_VK_DECIMAL or
|
||||
* // DOM_VK_DIVIDE.
|
||||
* // #2 If the key is Spacebar, use DOM_VK_SPACE.
|
||||
* //
|
||||
* // Following rules are printable keys in DOM_KEY_LOCATION_STANDARD.
|
||||
* // .keyCode value for a key shouldn't be changed by modifier states:
|
||||
* // #1 If the key can input [0-9] with any modifier state (except
|
||||
* // NumLock state), the value should be DOM_VK_[0-9].
|
||||
* // #2 Otherwise, and if the key inputs an ASCII alphabet with no
|
||||
* // active modifiers, use DOM_VK_[A-Z].
|
||||
* // #3 Otherwise, and if the key inputs an ASCII alphabet with no
|
||||
* // active modifiers except Shift key state, use DOM_VK_[A-Z] for
|
||||
* // the shifted character. E.g., if a key causes non-alphabet
|
||||
* // character such as "@" or a Unicode character without Shift key
|
||||
* // but "a" is inputted when Shift key is pressed, the proper
|
||||
* // keyCode is DOM_VK_A.
|
||||
* // #4 Otherwise, and if the key inputs another ASCII character with
|
||||
* // no modifier states, use a proper value for the character. E.g.,
|
||||
* // if the key inputs "*" without Shift key state, it should be
|
||||
* // DOM_VK_ASTERISK.
|
||||
* // #5 Otherwise, and if the key inputs another ASCII character with
|
||||
* // Shift key state, use a proper value for the character. E.g.,
|
||||
* // if a key causes a Unicode character without Shift key but "&"
|
||||
* // is inputted when Shift key is pressed, the proper keyCode is
|
||||
* // DOM_VK_AMPERSAND.
|
||||
* // See above document for the other cases.
|
||||
* //
|
||||
* // NOTE: If the software keyboard is 10-key like simple phone,
|
||||
* // We don't have common rules to decide its .keyCode value.
|
||||
* // Above rules should be used when the JS-Keyboard emulates PC
|
||||
* // keyboard.
|
||||
* // .key value should be inputting character by the key with current
|
||||
* // modifier state.
|
||||
* // .code value should be empty string if the JS-Keyboard isn't emulating
|
||||
* // physical keyboard. Otherwise, use same value with physical keyboard's
|
||||
* // same key.
|
||||
* var keyEvent = new KeyboardEvent("", { code: "KeyA", key: "a",
|
||||
* keyCode: KeyboardEvent.DOM_VK_A });
|
||||
* if (TIP.keydown(keyEvent)) {
|
||||
* // Handle its default action
|
||||
* }
|
||||
*
|
||||
* if (!TIP.beginInputTransaction(window, callback)) {
|
||||
* return; // You failed to get the rights to dispatch key events
|
||||
* }
|
||||
*
|
||||
* // Even if keydown event was consumed, keyup event should be dispatched.
|
||||
* if (TIP.keyup(keyEvent)) {
|
||||
* // Handle its default action
|
||||
* }
|
||||
*/
|
||||
|
||||
[scriptable, builtinclass, uuid(512f1efe-9e0f-48a4-b423-3936ef948f34)]
|
||||
[scriptable, builtinclass, uuid(60371ca6-a8a7-4e24-bf02-e262aa74ba5a)]
|
||||
interface nsITextInputProcessor : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -266,6 +360,59 @@ interface nsITextInputProcessor : nsISupports
|
||||
* this throws an exception.
|
||||
*/
|
||||
void cancelComposition();
|
||||
|
||||
// Specifying KEY_DEFAULT_PREVENTED can dispatch key events whose
|
||||
// defaultPrevented are true. Note that if this is specified, keypress event
|
||||
// won't be fired.
|
||||
const unsigned long KEY_DEFAULT_PREVENTED = 0x00000001;
|
||||
// If KEY_NON_PRINTABLE_KEY is specified and the .key value isn't valid
|
||||
// key name, the methods will throws an exception. In other words, this
|
||||
// flag prevents to dispatch key events with wrong key values and to cause
|
||||
// such key events input the key values as text.
|
||||
const unsigned long KEY_NON_PRINTABLE_KEY = 0x00000002;
|
||||
// If KEY_FORCE_PRINTABLE_KEY is specified and even if the .key value is a
|
||||
// registered key name, it's treated as inputting text value.
|
||||
const unsigned long KEY_FORCE_PRINTABLE_KEY = 0x00000004;
|
||||
|
||||
/**
|
||||
* keydown() may dispatch a keydown event and some keypress events if
|
||||
* preceding keydown event isn't consumed and they are necessary.
|
||||
* Note that even if this is called during composition, key events may not
|
||||
* be dispatched. In this case, this returns false.
|
||||
*
|
||||
* NOTE: Even if this has composition, JS-Keyboard should call keydown() and
|
||||
* keyup(). Although, with the default preferences and normal
|
||||
* conditions, DOM key events won't be fired during composition.
|
||||
* However, they MAY be dispatched for some reasons, e.g., the web
|
||||
* content listens only key events, or if the standard DOM event spec
|
||||
* will be changed in the future.
|
||||
*
|
||||
* @param aKeyboardEvent Must be a keyboard event which should be dispatched
|
||||
* as a keydown event and keypress events.
|
||||
* #1 Note that you don't need to set charCode value
|
||||
* because it's computed from its key value.
|
||||
* #2 If code value is set properly and location value
|
||||
* isn't specified (i.e., 0), the location value will
|
||||
* be guessed from the code value.
|
||||
* #3 Non-defined code names are not allowed. If your
|
||||
* key isn't registered, file a bug. If your key isn't
|
||||
* defined by any standards, use "" (empty string).
|
||||
* @param aKeyFlags Special flags. The values can be some of KEY_*
|
||||
* constants.
|
||||
* @return true if neither the keydown event or following
|
||||
* keypress events is *not* consumed.
|
||||
* Otherwise, i.e., preventDefault() is called, false.
|
||||
*/
|
||||
[optional_argc]
|
||||
boolean keydown(in nsIDOMKeyEvent aKeyboardEvent,
|
||||
[optional] in unsigned long aKeyFlags);
|
||||
|
||||
/**
|
||||
* Similar to keydown(), but this dispatches only a keyup event.
|
||||
*/
|
||||
[optional_argc]
|
||||
boolean keyup(in nsIDOMKeyEvent aKeyboardEvent,
|
||||
[optional] in unsigned long aKeyFlags);
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
Loading…
x
Reference in New Issue
Block a user