зеркало из https://github.com/mozilla/gecko-dev.git
Bug 936724 - Implement addInput/removeInput in InputMethod API. r=yxl, r=khuey
This commit is contained in:
Родитель
4e5dbde020
Коммит
7086ef24a8
|
@ -725,6 +725,8 @@ var CustomEventManager = {
|
|||
CaptivePortalLoginHelper.handleEvent(detail);
|
||||
break;
|
||||
case 'inputmethod-update-layouts':
|
||||
case 'inputregistry-add':
|
||||
case 'inputregistry-remove':
|
||||
KeyboardHelper.handleEvent(detail);
|
||||
break;
|
||||
case 'do-command':
|
||||
|
@ -868,7 +870,17 @@ let IndexedDBPromptHelper = {
|
|||
|
||||
let KeyboardHelper = {
|
||||
handleEvent: function keyboard_handleEvent(detail) {
|
||||
Keyboard.setLayouts(detail.layouts);
|
||||
switch (detail.type) {
|
||||
case 'inputmethod-update-layouts':
|
||||
Keyboard.setLayouts(detail.layouts);
|
||||
|
||||
break;
|
||||
case 'inputregistry-add':
|
||||
case 'inputregistry-remove':
|
||||
Keyboard.inputRegistryGlue.returnMessage(detail);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -19,6 +19,36 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
|
||||
"resource://gre/modules/SystemAppProxy.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "appsService", function() {
|
||||
return Cc["@mozilla.org/AppsService;1"].getService(Ci.nsIAppsService);
|
||||
});
|
||||
|
||||
let Utils = {
|
||||
getMMFromMessage: function u_getMMFromMessage(msg) {
|
||||
let mm;
|
||||
try {
|
||||
mm = msg.target.QueryInterface(Ci.nsIFrameLoaderOwner)
|
||||
.frameLoader.messageManager;
|
||||
} catch(e) {
|
||||
mm = msg.target;
|
||||
}
|
||||
|
||||
return mm;
|
||||
},
|
||||
checkPermissionForMM: function u_checkPermissionForMM(mm, permName) {
|
||||
let testing = false;
|
||||
try {
|
||||
testing = Services.prefs.getBoolPref("dom.mozInputMethod.testing");
|
||||
} catch (e) { }
|
||||
|
||||
if (testing) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return mm.assertPermission(permName);
|
||||
}
|
||||
};
|
||||
|
||||
this.Keyboard = {
|
||||
_formMM: null, // The current web page message manager.
|
||||
_keyboardMM: null, // The keyboard app message manager.
|
||||
|
@ -72,6 +102,8 @@ this.Keyboard = {
|
|||
for (let name of this._systemMessageName) {
|
||||
ppmm.addMessageListener('System:' + name, this);
|
||||
}
|
||||
|
||||
this.inputRegistryGlue = new InputRegistryGlue();
|
||||
},
|
||||
|
||||
observe: function keyboardObserve(subject, topic, data) {
|
||||
|
@ -122,12 +154,7 @@ this.Keyboard = {
|
|||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mm = msg.target.QueryInterface(Ci.nsIFrameLoaderOwner)
|
||||
.frameLoader.messageManager;
|
||||
} catch(e) {
|
||||
mm = msg.target;
|
||||
}
|
||||
mm = Utils.getMMFromMessage(msg);
|
||||
|
||||
// That should never happen.
|
||||
if (!mm) {
|
||||
|
@ -135,16 +162,10 @@ this.Keyboard = {
|
|||
return;
|
||||
}
|
||||
|
||||
let testing = false;
|
||||
try {
|
||||
testing = Services.prefs.getBoolPref("dom.mozInputMethod.testing");
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
let perm = (msg.name.indexOf("Keyboard:") === 0) ? "input"
|
||||
: "input-manage";
|
||||
if (!isKeyboardRegistration && !testing &&
|
||||
!mm.assertPermission(perm)) {
|
||||
|
||||
if (!isKeyboardRegistration && !Utils.checkPermissionForMM(mm, perm)) {
|
||||
dump("Keyboard message " + msg.name +
|
||||
" from a content process with no '" + perm + "' privileges.");
|
||||
return;
|
||||
|
@ -364,4 +385,93 @@ this.Keyboard = {
|
|||
}
|
||||
};
|
||||
|
||||
function InputRegistryGlue() {
|
||||
this._messageId = 0;
|
||||
this._msgMap = new Map();
|
||||
|
||||
ppmm.addMessageListener('InputRegistry:Add', this);
|
||||
ppmm.addMessageListener('InputRegistry:Remove', this);
|
||||
};
|
||||
|
||||
InputRegistryGlue.prototype.receiveMessage = function(msg) {
|
||||
let mm = Utils.getMMFromMessage(msg);
|
||||
|
||||
if (!Utils.checkPermissionForMM(mm, 'input')) {
|
||||
dump("InputRegistryGlue message " + msg.name +
|
||||
" from a content process with no 'input' privileges.");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (msg.name) {
|
||||
case 'InputRegistry:Add':
|
||||
this.addInput(msg, mm);
|
||||
|
||||
break;
|
||||
|
||||
case 'InputRegistry:Remove':
|
||||
this.removeInput(msg, mm);
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
InputRegistryGlue.prototype.addInput = function(msg, mm) {
|
||||
let msgId = this._messageId++;
|
||||
this._msgMap.set(msgId, {
|
||||
mm: mm,
|
||||
requestId: msg.data.requestId
|
||||
});
|
||||
|
||||
let manifestURL = appsService.getManifestURLByLocalId(msg.data.appId);
|
||||
|
||||
SystemAppProxy.dispatchEvent({
|
||||
type: 'inputregistry-add',
|
||||
id: msgId,
|
||||
manifestURL: manifestURL,
|
||||
inputId: msg.data.inputId,
|
||||
inputManifest: msg.data.inputManifest
|
||||
});
|
||||
};
|
||||
|
||||
InputRegistryGlue.prototype.removeInput = function(msg, mm) {
|
||||
let msgId = this._messageId++;
|
||||
this._msgMap.set(msgId, {
|
||||
mm: mm,
|
||||
requestId: msg.data.requestId
|
||||
});
|
||||
|
||||
let manifestURL = appsService.getManifestURLByLocalId(msg.data.appId);
|
||||
|
||||
SystemAppProxy.dispatchEvent({
|
||||
type: 'inputregistry-remove',
|
||||
id: msgId,
|
||||
manifestURL: manifestURL,
|
||||
inputId: msg.data.inputId
|
||||
});
|
||||
};
|
||||
|
||||
InputRegistryGlue.prototype.returnMessage = function(detail) {
|
||||
if (!this._msgMap.has(detail.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let { mm, requestId } = this._msgMap.get(detail.id);
|
||||
this._msgMap.delete(detail.id);
|
||||
|
||||
if (Cu.isDeadWrapper(mm)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!('error' in detail)) {
|
||||
mm.sendAsyncMessage('InputRegistry:Result:OK', {
|
||||
requestId: requestId
|
||||
});
|
||||
} else {
|
||||
mm.sendAsyncMessage('InputRegistry:Result:Error', {
|
||||
error: detail.error,
|
||||
requestId: requestId
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.Keyboard.init();
|
||||
|
|
|
@ -149,6 +149,8 @@ MozInputMethodManager.prototype = {
|
|||
function MozInputMethod() { }
|
||||
|
||||
MozInputMethod.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
_inputcontext: null,
|
||||
_wrappedInputContext: null,
|
||||
_layouts: {},
|
||||
|
@ -196,6 +198,8 @@ MozInputMethod.prototype = {
|
|||
cpmm.addWeakMessageListener('Keyboard:SelectionChange', this);
|
||||
cpmm.addWeakMessageListener('Keyboard:GetContext:Result:OK', this);
|
||||
cpmm.addWeakMessageListener('Keyboard:LayoutsChange', this);
|
||||
cpmm.addWeakMessageListener('InputRegistry:Result:OK', this);
|
||||
cpmm.addWeakMessageListener('InputRegistry:Result:Error', this);
|
||||
},
|
||||
|
||||
uninit: function mozInputMethodUninit() {
|
||||
|
@ -210,21 +214,26 @@ MozInputMethod.prototype = {
|
|||
cpmm.removeWeakMessageListener('Keyboard:SelectionChange', this);
|
||||
cpmm.removeWeakMessageListener('Keyboard:GetContext:Result:OK', this);
|
||||
cpmm.removeWeakMessageListener('Keyboard:LayoutsChange', this);
|
||||
cpmm.removeWeakMessageListener('InputRegistry:Result:OK', this);
|
||||
cpmm.removeWeakMessageListener('InputRegistry:Result:Error', this);
|
||||
this.setActive(false);
|
||||
},
|
||||
|
||||
receiveMessage: function mozInputMethodReceiveMsg(msg) {
|
||||
if (!WindowMap.isActive(this._window)) {
|
||||
if (!msg.name.startsWith('InputRegistry') &&
|
||||
!WindowMap.isActive(this._window)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let json = msg.json;
|
||||
let data = msg.data;
|
||||
let resolver = ('requestId' in data) ?
|
||||
this.takePromiseResolver(data.requestId) : null;
|
||||
|
||||
switch(msg.name) {
|
||||
case 'Keyboard:FocusChange':
|
||||
if (json.type !== 'blur') {
|
||||
if (data.type !== 'blur') {
|
||||
// XXX Bug 904339 could receive 'text' event twice
|
||||
this.setInputContext(json);
|
||||
this.setInputContext(data);
|
||||
}
|
||||
else {
|
||||
this.setInputContext(null);
|
||||
|
@ -232,14 +241,24 @@ MozInputMethod.prototype = {
|
|||
break;
|
||||
case 'Keyboard:SelectionChange':
|
||||
if (this.inputcontext) {
|
||||
this._inputcontext.updateSelectionContext(json, false);
|
||||
this._inputcontext.updateSelectionContext(data, false);
|
||||
}
|
||||
break;
|
||||
case 'Keyboard:GetContext:Result:OK':
|
||||
this.setInputContext(json);
|
||||
this.setInputContext(data);
|
||||
break;
|
||||
case 'Keyboard:LayoutsChange':
|
||||
this._layouts = json;
|
||||
this._layouts = data;
|
||||
break;
|
||||
|
||||
case 'InputRegistry:Result:OK':
|
||||
resolver.resolve();
|
||||
|
||||
break;
|
||||
|
||||
case 'InputRegistry:Result:Error':
|
||||
resolver.reject(data.error);
|
||||
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
@ -330,6 +349,31 @@ MozInputMethod.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
addInput: function(inputId, inputManifest) {
|
||||
return this._sendPromise(function(resolverId) {
|
||||
let appId = this._window.document.nodePrincipal.appId;
|
||||
|
||||
cpmm.sendAsyncMessage('InputRegistry:Add', {
|
||||
requestId: resolverId,
|
||||
inputId: inputId,
|
||||
inputManifest: inputManifest,
|
||||
appId: appId
|
||||
});
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
removeInput: function(inputId) {
|
||||
return this._sendPromise(function(resolverId) {
|
||||
let appId = this._window.document.nodePrincipal.appId;
|
||||
|
||||
cpmm.sendAsyncMessage('InputRegistry:Remove', {
|
||||
requestId: resolverId,
|
||||
inputId: inputId,
|
||||
appId: appId
|
||||
});
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
setValue: function(value) {
|
||||
this._ensureIsSystem();
|
||||
cpmm.sendAsyncMessage('System:SetValue', {
|
||||
|
@ -361,6 +405,14 @@ MozInputMethod.prototype = {
|
|||
throw new this._window.DOMError("Security",
|
||||
"Should have 'input-manage' permssion.");
|
||||
}
|
||||
},
|
||||
|
||||
_sendPromise: function(callback) {
|
||||
let self = this;
|
||||
return this.createPromise(function(resolve, reject) {
|
||||
let resolverId = self.getPromiseResolverId({ resolve: resolve, reject: reject });
|
||||
callback(resolverId);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -29,6 +29,20 @@ interface MozInputMethod : EventTarget {
|
|||
// Activate or decactive current input method window.
|
||||
void setActive(boolean isActive);
|
||||
|
||||
// Add a dynamically declared input.
|
||||
//
|
||||
// The id must not be the same with any statically declared input in the app
|
||||
// manifest. If an input of the same id is already declared, the info of that
|
||||
// input will be updated.
|
||||
Promise<void> addInput(DOMString inputId, object inputManifest);
|
||||
|
||||
// Remove a dynamically declared input.
|
||||
//
|
||||
// The id must not be the same with any statically declared input in the app
|
||||
// manifest. Silently resolves if the input is not previously declared;
|
||||
// rejects if attempt to remove a statically declared input.
|
||||
Promise<void> removeInput(DOMString id);
|
||||
|
||||
// The following are internal methods for Firefox OS system app only.
|
||||
|
||||
// Set the value on the currently focused element. This has to be used
|
||||
|
|
Загрузка…
Ссылка в новой задаче