зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1137557 - Part 2: Remove sendKeyEvent from forms.js. r=masayuki, r=smaug (to make the webidl hook happy)
--HG-- extra : source : 83af10efcd3ced1f1ffaa202aeea7de03cf096f9
This commit is contained in:
Родитель
653afd145a
Коммит
877fd2b4fe
|
@ -740,13 +740,15 @@ MozInputContext.prototype = {
|
|||
|
||||
sendKey: function ic_sendKey(keyCode, charCode, modifiers, repeat) {
|
||||
let self = this;
|
||||
|
||||
// XXX: modifiers are ignored in this API method.
|
||||
|
||||
return this._sendPromise(function(resolverId) {
|
||||
cpmmSendAsyncMessageWithKbID(self, 'Keyboard:SendKey', {
|
||||
contextId: self._contextId,
|
||||
requestId: resolverId,
|
||||
keyCode: keyCode,
|
||||
charCode: charCode,
|
||||
modifiers: modifiers,
|
||||
repeat: repeat
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,10 +18,50 @@ XPCOMUtils.defineLazyServiceGetter(Services, "fm",
|
|||
"@mozilla.org/focus-manager;1",
|
||||
"nsIFocusManager");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "domWindowUtils", function () {
|
||||
return content.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
});
|
||||
/*
|
||||
* A WeakMap to map window to objects keeping it's TextInputProcessor instance.
|
||||
*/
|
||||
let WindowMap = {
|
||||
// WeakMap of <window, object> pairs.
|
||||
_map: null,
|
||||
|
||||
/*
|
||||
* Set the object associated to the window and return it.
|
||||
*/
|
||||
_getObjForWin: function(win) {
|
||||
if (!this._map) {
|
||||
this._map = new WeakMap();
|
||||
}
|
||||
if (this._map.has(win)) {
|
||||
return this._map.get(win);
|
||||
} else {
|
||||
let obj = {
|
||||
tip: null
|
||||
};
|
||||
this._map.set(win, obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
},
|
||||
|
||||
getTextInputProcessor: function(win) {
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
let obj = this._getObjForWin(win);
|
||||
let tip = obj.tip
|
||||
|
||||
if (!tip) {
|
||||
tip = obj.tip = Cc["@mozilla.org/text-input-processor;1"]
|
||||
.createInstance(Ci.nsITextInputProcessor);
|
||||
}
|
||||
|
||||
if (!tip.beginInputTransaction(win, textInputProcessorCallback)) {
|
||||
tip = obj.tip = null;
|
||||
}
|
||||
return tip;
|
||||
}
|
||||
};
|
||||
|
||||
const RESIZE_SCROLL_DELAY = 20;
|
||||
// In content editable node, when there are hidden elements such as <br>, it
|
||||
|
@ -41,6 +81,151 @@ let HTMLSelectElement = Ci.nsIDOMHTMLSelectElement;
|
|||
let HTMLOptGroupElement = Ci.nsIDOMHTMLOptGroupElement;
|
||||
let HTMLOptionElement = Ci.nsIDOMHTMLOptionElement;
|
||||
|
||||
function guessKeyNameFromKeyCode(KeyboardEvent, aKeyCode) {
|
||||
switch (aKeyCode) {
|
||||
case KeyboardEvent.DOM_VK_CANCEL:
|
||||
return "Cancel";
|
||||
case KeyboardEvent.DOM_VK_HELP:
|
||||
return "Help";
|
||||
case KeyboardEvent.DOM_VK_BACK_SPACE:
|
||||
return "Backspace";
|
||||
case KeyboardEvent.DOM_VK_TAB:
|
||||
return "Tab";
|
||||
case KeyboardEvent.DOM_VK_CLEAR:
|
||||
return "Clear";
|
||||
case KeyboardEvent.DOM_VK_RETURN:
|
||||
return "Enter";
|
||||
case KeyboardEvent.DOM_VK_SHIFT:
|
||||
return "Shift";
|
||||
case KeyboardEvent.DOM_VK_CONTROL:
|
||||
return "Control";
|
||||
case KeyboardEvent.DOM_VK_ALT:
|
||||
return "Alt";
|
||||
case KeyboardEvent.DOM_VK_PAUSE:
|
||||
return "Pause";
|
||||
case KeyboardEvent.DOM_VK_EISU:
|
||||
return "Eisu";
|
||||
case KeyboardEvent.DOM_VK_ESCAPE:
|
||||
return "Escape";
|
||||
case KeyboardEvent.DOM_VK_CONVERT:
|
||||
return "Convert";
|
||||
case KeyboardEvent.DOM_VK_NONCONVERT:
|
||||
return "NonConvert";
|
||||
case KeyboardEvent.DOM_VK_ACCEPT:
|
||||
return "Accept";
|
||||
case KeyboardEvent.DOM_VK_MODECHANGE:
|
||||
return "ModeChange";
|
||||
case KeyboardEvent.DOM_VK_PAGE_UP:
|
||||
return "PageUp";
|
||||
case KeyboardEvent.DOM_VK_PAGE_DOWN:
|
||||
return "PageDown";
|
||||
case KeyboardEvent.DOM_VK_END:
|
||||
return "End";
|
||||
case KeyboardEvent.DOM_VK_HOME:
|
||||
return "Home";
|
||||
case KeyboardEvent.DOM_VK_LEFT:
|
||||
return "ArrowLeft";
|
||||
case KeyboardEvent.DOM_VK_UP:
|
||||
return "ArrowUp";
|
||||
case KeyboardEvent.DOM_VK_RIGHT:
|
||||
return "ArrowRight";
|
||||
case KeyboardEvent.DOM_VK_DOWN:
|
||||
return "ArrowDown";
|
||||
case KeyboardEvent.DOM_VK_SELECT:
|
||||
return "Select";
|
||||
case KeyboardEvent.DOM_VK_PRINT:
|
||||
return "Print";
|
||||
case KeyboardEvent.DOM_VK_EXECUTE:
|
||||
return "Execute";
|
||||
case KeyboardEvent.DOM_VK_PRINTSCREEN:
|
||||
return "PrintScreen";
|
||||
case KeyboardEvent.DOM_VK_INSERT:
|
||||
return "Insert";
|
||||
case KeyboardEvent.DOM_VK_DELETE:
|
||||
return "Delete";
|
||||
case KeyboardEvent.DOM_VK_WIN:
|
||||
return "OS";
|
||||
case KeyboardEvent.DOM_VK_CONTEXT_MENU:
|
||||
return "ContextMenu";
|
||||
case KeyboardEvent.DOM_VK_SLEEP:
|
||||
return "Standby";
|
||||
case KeyboardEvent.DOM_VK_F1:
|
||||
return "F1";
|
||||
case KeyboardEvent.DOM_VK_F2:
|
||||
return "F2";
|
||||
case KeyboardEvent.DOM_VK_F3:
|
||||
return "F3";
|
||||
case KeyboardEvent.DOM_VK_F4:
|
||||
return "F4";
|
||||
case KeyboardEvent.DOM_VK_F5:
|
||||
return "F5";
|
||||
case KeyboardEvent.DOM_VK_F6:
|
||||
return "F6";
|
||||
case KeyboardEvent.DOM_VK_F7:
|
||||
return "F7";
|
||||
case KeyboardEvent.DOM_VK_F8:
|
||||
return "F8";
|
||||
case KeyboardEvent.DOM_VK_F9:
|
||||
return "F9";
|
||||
case KeyboardEvent.DOM_VK_F10:
|
||||
return "F10";
|
||||
case KeyboardEvent.DOM_VK_F11:
|
||||
return "F11";
|
||||
case KeyboardEvent.DOM_VK_F12:
|
||||
return "F12";
|
||||
case KeyboardEvent.DOM_VK_F13:
|
||||
return "F13";
|
||||
case KeyboardEvent.DOM_VK_F14:
|
||||
return "F14";
|
||||
case KeyboardEvent.DOM_VK_F15:
|
||||
return "F15";
|
||||
case KeyboardEvent.DOM_VK_F16:
|
||||
return "F16";
|
||||
case KeyboardEvent.DOM_VK_F17:
|
||||
return "F17";
|
||||
case KeyboardEvent.DOM_VK_F18:
|
||||
return "F18";
|
||||
case KeyboardEvent.DOM_VK_F19:
|
||||
return "F19";
|
||||
case KeyboardEvent.DOM_VK_F20:
|
||||
return "F20";
|
||||
case KeyboardEvent.DOM_VK_F21:
|
||||
return "F21";
|
||||
case KeyboardEvent.DOM_VK_F22:
|
||||
return "F22";
|
||||
case KeyboardEvent.DOM_VK_F23:
|
||||
return "F23";
|
||||
case KeyboardEvent.DOM_VK_F24:
|
||||
return "F24";
|
||||
case KeyboardEvent.DOM_VK_NUM_LOCK:
|
||||
return "NumLock";
|
||||
case KeyboardEvent.DOM_VK_SCROLL_LOCK:
|
||||
return "ScrollLock";
|
||||
case KeyboardEvent.DOM_VK_VOLUME_MUTE:
|
||||
return "VolumeMute";
|
||||
case KeyboardEvent.DOM_VK_VOLUME_DOWN:
|
||||
return "VolumeDown";
|
||||
case KeyboardEvent.DOM_VK_VOLUME_UP:
|
||||
return "VolumeUp";
|
||||
case KeyboardEvent.DOM_VK_META:
|
||||
return "Meta";
|
||||
case KeyboardEvent.DOM_VK_ALTGR:
|
||||
return "AltGraph";
|
||||
case KeyboardEvent.DOM_VK_ATTN:
|
||||
return "Attn";
|
||||
case KeyboardEvent.DOM_VK_CRSEL:
|
||||
return "CrSel";
|
||||
case KeyboardEvent.DOM_VK_EXSEL:
|
||||
return "ExSel";
|
||||
case KeyboardEvent.DOM_VK_EREOF:
|
||||
return "EraseEof";
|
||||
case KeyboardEvent.DOM_VK_PLAY:
|
||||
return "Play";
|
||||
default:
|
||||
return "Unidentified";
|
||||
}
|
||||
}
|
||||
|
||||
let FormVisibility = {
|
||||
/**
|
||||
* Searches upwards in the DOM for an element that has been scrolled.
|
||||
|
@ -184,6 +369,41 @@ let FormVisibility = {
|
|||
}
|
||||
};
|
||||
|
||||
// This object implements nsITextInputProcessorCallback
|
||||
let textInputProcessorCallback = {
|
||||
onNotify: function(aTextInputProcessor, aNotification) {
|
||||
try {
|
||||
switch (aNotification.type) {
|
||||
case "request-to-commit":
|
||||
// TODO: Send a notification through asyncMessage to the keyboard here.
|
||||
aTextInputProcessor.commitComposition();
|
||||
|
||||
break;
|
||||
case "request-to-cancel":
|
||||
// TODO: Send a notification through asyncMessage to the keyboard here.
|
||||
aTextInputProcessor.cancelComposition();
|
||||
|
||||
break;
|
||||
|
||||
case "notify-detached":
|
||||
// TODO: Send a notification through asyncMessage to the keyboard here.
|
||||
break;
|
||||
|
||||
// TODO: Manage _focusedElement for text input from here instead.
|
||||
// (except for <select> which will be need to handled elsewhere)
|
||||
case "notify-focus":
|
||||
break;
|
||||
|
||||
case "notify-blur":
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
let FormAssistant = {
|
||||
init: function fa_init() {
|
||||
addEventListener("focus", this, true, false);
|
||||
|
@ -502,34 +722,87 @@ let FormAssistant = {
|
|||
case "Forms:Input:SendKey":
|
||||
CompositionManager.endComposition('');
|
||||
|
||||
let flags = domWindowUtils.KEY_FLAG_NOT_SYNTHESIZED_FOR_TESTS;
|
||||
this._editing = true;
|
||||
let doKeypress = domWindowUtils.sendKeyEvent('keydown', json.keyCode,
|
||||
json.charCode, json.modifiers, flags);
|
||||
if (doKeypress) {
|
||||
domWindowUtils.sendKeyEvent('keypress', json.keyCode,
|
||||
json.charCode, json.modifiers, flags);
|
||||
let win = target.ownerDocument.defaultView;
|
||||
let tip = WindowMap.getTextInputProcessor(win);
|
||||
if (!tip) {
|
||||
if (json.requestId) {
|
||||
sendAsyncMessage("Forms:SendKey:Result:Error", {
|
||||
requestId: json.requestId,
|
||||
error: "Unable to start input transaction."
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(!json.repeat) {
|
||||
domWindowUtils.sendKeyEvent('keyup', json.keyCode,
|
||||
json.charCode, json.modifiers, flags);
|
||||
// The naive way to figure out if the key to dispatch is printable.
|
||||
let printable = !!json.charCode;
|
||||
|
||||
let keyboardEventDict = {
|
||||
// For printable keys, the value should be the actual character.
|
||||
// For non-printable keys, it should be a value in the D3E spec.
|
||||
// Here we make some educated guess for it.
|
||||
key: printable ?
|
||||
String.fromCharCode(json.charCode) :
|
||||
guessKeyNameFromKeyCode(win.KeyboardEvent, json.keyCode),
|
||||
// We don't have any information to tell the virtual key the
|
||||
// user have interacted with.
|
||||
code: "",
|
||||
// We violate the spec here and ask TextInputProcessor not to infer
|
||||
// this value from value of key nor code so we could keep the original
|
||||
// behavior.
|
||||
keyCode: json.keyCode,
|
||||
// We do not have the information to infer location of the virtual key
|
||||
// either (and we would need TextInputProcessor not to compute it).
|
||||
location: 0,
|
||||
// This indicates the key is triggered for repeats.
|
||||
repeat: json.repeat
|
||||
};
|
||||
|
||||
let keyboardEvent = new win.KeyboardEvent("", keyboardEventDict);
|
||||
let flags = tip.KEY_KEEP_KEY_LOCATION_STANDARD;
|
||||
if (!printable) {
|
||||
flags |= tip.KEY_NON_PRINTABLE_KEY;
|
||||
}
|
||||
if (!json.keyCode) {
|
||||
flags |= tip.KEY_KEEP_KEYCODE_ZERO;
|
||||
}
|
||||
|
||||
this._editing = false;
|
||||
let keydownDefaultPrevented;
|
||||
try {
|
||||
let consumedFlags = tip.keydown(keyboardEvent, flags);
|
||||
keydownDefaultPrevented =
|
||||
!!(tip.KEYDOWN_IS_CONSUMED & consumedFlags);
|
||||
if (!json.repeat) {
|
||||
tip.keyup(keyboardEvent, flags);
|
||||
}
|
||||
} catch (e) {
|
||||
dump("forms.js:" + e.toString() + "\n");
|
||||
|
||||
if (json.requestId && doKeypress) {
|
||||
sendAsyncMessage("Forms:SendKey:Result:OK", {
|
||||
requestId: json.requestId,
|
||||
selectioninfo: this.getSelectionInfo()
|
||||
});
|
||||
if (json.requestId) {
|
||||
sendAsyncMessage("Forms:SendKey:Result:Error", {
|
||||
requestId: json.requestId,
|
||||
error: "Unable to type into destoryed input."
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else if (json.requestId && !doKeypress) {
|
||||
sendAsyncMessage("Forms:SendKey:Result:Error", {
|
||||
requestId: json.requestId,
|
||||
error: "Keydown event got canceled"
|
||||
});
|
||||
|
||||
if (json.requestId) {
|
||||
if (keydownDefaultPrevented) {
|
||||
sendAsyncMessage("Forms:SendKey:Result:Error", {
|
||||
requestId: json.requestId,
|
||||
error: "Key event(s) was cancelled."
|
||||
});
|
||||
} else {
|
||||
sendAsyncMessage("Forms:SendKey:Result:OK", {
|
||||
requestId: json.requestId,
|
||||
selectioninfo: this.getSelectionInfo()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "Forms:Select:Choice":
|
||||
|
@ -1170,7 +1443,7 @@ function replaceSurroundingText(element, text, offset, length) {
|
|||
|
||||
let CompositionManager = {
|
||||
_isStarted: false,
|
||||
_textInputProcessor: null,
|
||||
_tip: null,
|
||||
_clauseAttrMap: {
|
||||
'raw-input':
|
||||
Ci.nsITextInputProcessor.ATTR_RAW_CLAUSE,
|
||||
|
@ -1182,34 +1455,6 @@ let CompositionManager = {
|
|||
Ci.nsITextInputProcessor.ATTR_SELECTED_CLAUSE
|
||||
},
|
||||
|
||||
_callback: function cm_callback(aTIP, aNotification)
|
||||
{
|
||||
try {
|
||||
switch (aNotification.type) {
|
||||
case "request-to-commit":
|
||||
aTIP.commitComposition();
|
||||
break;
|
||||
case "request-to-cancel":
|
||||
aTIP.cancelComposition();
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
_prepareTextInputProcessor: function cm_prepareTextInputProcessor(aWindow)
|
||||
{
|
||||
if (!this._textInputProcessor) {
|
||||
this._textInputProcessor =
|
||||
Cc["@mozilla.org/text-input-processor;1"].
|
||||
createInstance(Ci.nsITextInputProcessor);
|
||||
}
|
||||
return this._textInputProcessor.beginInputTransaction(aWindow,
|
||||
this._callback);
|
||||
},
|
||||
|
||||
setComposition: function cm_setComposition(element, text, cursor, clauses) {
|
||||
// Check parameters.
|
||||
if (!element) {
|
||||
|
@ -1248,30 +1493,39 @@ let CompositionManager = {
|
|||
}
|
||||
|
||||
let win = element.ownerDocument.defaultView;
|
||||
if (!this._prepareTextInputProcessor(win)) {
|
||||
let tip = WindowMap.getTextInputProcessor(win);
|
||||
if (!tip) {
|
||||
return;
|
||||
}
|
||||
// Update the composing text.
|
||||
this._textInputProcessor.setPendingCompositionString(text);
|
||||
tip.setPendingCompositionString(text);
|
||||
for (var i = 0; i < clauseLens.length; i++) {
|
||||
if (!clauseLens[i]) {
|
||||
continue;
|
||||
}
|
||||
this._textInputProcessor.appendClauseToPendingComposition(clauseLens[i],
|
||||
clauseAttrs[i]);
|
||||
tip.appendClauseToPendingComposition(clauseLens[i], clauseAttrs[i]);
|
||||
}
|
||||
if (cursor >= 0) {
|
||||
this._textInputProcessor.setCaretInPendingComposition(cursor);
|
||||
tip.setCaretInPendingComposition(cursor);
|
||||
}
|
||||
this._isStarted = tip.flushPendingComposition();
|
||||
if (this._isStarted) {
|
||||
this._tip = tip;
|
||||
}
|
||||
this._isStarted = this._textInputProcessor.flushPendingComposition();
|
||||
},
|
||||
|
||||
endComposition: function cm_endComposition(text) {
|
||||
if (!this._isStarted) {
|
||||
return;
|
||||
}
|
||||
this._textInputProcessor.commitCompositionWith(text ? text : "");
|
||||
let tip = this._tip;
|
||||
if (!tip) {
|
||||
return;
|
||||
}
|
||||
|
||||
tip.commitCompositionWith(text ? text : "");
|
||||
this._isStarted = false;
|
||||
this._tip = null;
|
||||
},
|
||||
|
||||
// Composition ends due to external actions.
|
||||
|
@ -1281,5 +1535,6 @@ let CompositionManager = {
|
|||
}
|
||||
|
||||
this._isStarted = false;
|
||||
this._tip = null;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -193,7 +193,7 @@ interface MozInputContext: EventTarget {
|
|||
|
||||
/*
|
||||
* send a character with its key events.
|
||||
* @param modifiers see http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/base/nsIDOMWindowUtils.idl#206
|
||||
* @param modifiers this paramater is no longer honored.
|
||||
* @param repeat indicates whether a key would be sent repeatedly.
|
||||
* @return true if succeeds. Otherwise false if the input context becomes void.
|
||||
* Alternative: sendKey(KeyboardEvent event), but we will likely
|
||||
|
|
Загрузка…
Ссылка в новой задаче