Bug 1197682 - InputMethodManager#setSupportsSwitchingTypes, r=janjongboom, sr=smaug

This commit is contained in:
Tim Chien 2015-09-10 22:29:00 +02:00
Родитель 4d5d75f626
Коммит 5c6b996776
5 изменённых файлов: 226 добавлений и 44 удалений

Просмотреть файл

@ -45,8 +45,10 @@ this.Keyboard = {
_keyboardMM: null, // The keyboard app message manager.
_keyboardID: -1, // The keyboard app's ID number. -1 = invalid
_nextKeyboardID: 0, // The ID number counter.
_systemMessageName: [
'SetValue', 'RemoveFocus', 'SetSelectedOption', 'SetSelectedOptions'
_supportsSwitchingTypes: [],
_systemMessageNames: [
'SetValue', 'RemoveFocus', 'SetSelectedOption', 'SetSelectedOptions',
'SetSupportsSwitchingTypes'
],
_messageNames: [
@ -70,6 +72,12 @@ this.Keyboard = {
},
sendToForm: function(name, data) {
if (!this.formMM) {
dump("Keyboard.jsm: Attempt to send message " + name +
" to form but no message manager exists.\n");
return;
}
try {
this.formMM.sendAsyncMessage(name, data);
} catch(e) { }
@ -91,7 +99,7 @@ this.Keyboard = {
ppmm.addMessageListener('Keyboard:' + name, this);
}
for (let name of this._systemMessageName) {
for (let name of this._systemMessageNames) {
ppmm.addMessageListener('System:' + name, this);
}
@ -110,7 +118,7 @@ this.Keyboard = {
}
if (topic == 'oop-frameloader-crashed' ||
topic == 'message-manager-close') {
topic == 'message-manager-close') {
if (this.formMM == mm) {
// The application has been closed unexpectingly. Let's tell the
// keyboard app that the focus has been lost.
@ -152,28 +160,26 @@ this.Keyboard = {
// If we get a 'Keyboard:XXX'/'System:XXX' message, check that the sender
// has the required permission.
let mm;
let isKeyboardRegistration = msg.name == "Keyboard:Register" ||
msg.name == "Keyboard:Unregister";
if (msg.name.indexOf("Keyboard:") === 0 ||
msg.name.indexOf("System:") === 0) {
if (!this.formMM && !isKeyboardRegistration) {
return;
}
// Assert the permission based on the prefix of the message.
let permName;
if (msg.name.startsWith("Keyboard:")) {
permName = "input";
} else if (msg.name.startsWith("System:")) {
permName = "input-manage";
}
// There is no permission to check (nor we need to get the mm)
// for Form: messages.
if (permName) {
mm = Utils.getMMFromMessage(msg);
// That should never happen.
if (!mm) {
dump("!! No message manager found for " + msg.name);
dump("Keyboard.jsm: Message " + msg.name + " has no message manager.");
return;
}
let perm = (msg.name.indexOf("Keyboard:") === 0) ? "input"
: "input-manage";
if (!isKeyboardRegistration && !Utils.checkPermissionForMM(mm, perm)) {
dump("Keyboard message " + msg.name +
" from a content process with no '" + perm + "' privileges.");
if (!Utils.checkPermissionForMM(mm, permName)) {
dump("Keyboard.jsm: Message " + msg.name +
" from a content process with no '" + permName + "' privileges.");
return;
}
}
@ -229,6 +235,9 @@ this.Keyboard = {
case 'System:SetSelectedOptions':
this.setSelectedOption(msg);
break;
case 'System:SetSupportsSwitchingTypes':
this.setSupportsSwitchingTypes(msg);
break;
case 'Keyboard:SetSelectionRange':
this.setSelectionRange(msg);
break;
@ -341,6 +350,10 @@ this.Keyboard = {
},
removeFocus: function keyboardRemoveFocus() {
if (!this.formMM) {
return;
}
this.sendToForm('Forms:Select:Blur', {});
},
@ -369,10 +382,14 @@ this.Keyboard = {
},
getContext: function keyboardGetContext(msg) {
if (this._layouts) {
this.sendToKeyboard('Keyboard:LayoutsChange', this._layouts);
if (!this.formMM) {
return;
}
this.sendToKeyboard('Keyboard:SupportsSwitchingTypesChange', {
types: this._supportsSwitchingTypes
});
this.sendToForm('Forms:GetContext', msg.data);
},
@ -384,17 +401,28 @@ this.Keyboard = {
this.sendToForm('Forms:EndComposition', msg.data);
},
/**
* Get the number of keyboard layouts active from keyboard_manager
*/
_layouts: null,
setLayouts: function keyboardSetLayoutCount(layouts) {
setSupportsSwitchingTypes: function setSupportsSwitchingTypes(msg) {
this._supportsSwitchingTypes = msg.data.types;
this.sendToKeyboard('Keyboard:SupportsSwitchingTypesChange', msg.data);
},
// XXX: To be removed with mozContentEvent support from shell.js
setLayouts: function keyboardSetLayouts(layouts) {
// The input method plugins may not have loaded yet,
// cache the layouts so on init we can respond immediately instead
// of going back and forth between keyboard_manager
this._layouts = layouts;
var types = [];
this.sendToKeyboard('Keyboard:LayoutsChange', layouts);
Object.keys(layouts).forEach((type) => {
if (layouts[type] > 1) {
types.push(type);
}
});
this._supportsSwitchingTypes = types;
this.sendToKeyboard('Keyboard:SupportsSwitchingTypesChange', {
types: types
});
}
};

Просмотреть файл

@ -136,7 +136,7 @@ function MozInputMethodManager(win) {
}
MozInputMethodManager.prototype = {
_supportsSwitching: false,
supportsSwitchingForCurrentInputContext: false,
_window: null,
classID: Components.ID("{7e9d7280-ef86-11e2-b778-0800200c9a66}"),
@ -161,7 +161,7 @@ MozInputMethodManager.prototype = {
if (!WindowMap.isActive(this._window)) {
return false;
}
return this._supportsSwitching;
return this.supportsSwitchingForCurrentInputContext;
},
hide: function() {
@ -169,6 +169,12 @@ MozInputMethodManager.prototype = {
return;
}
cpmmSendAsyncMessageWithKbID(this, 'Keyboard:RemoveFocus', {});
},
setSupportsSwitchingTypes: function(types) {
cpmm.sendAsyncMessage('System:SetSupportsSwitchingTypes', {
types: types
});
}
};
@ -184,7 +190,7 @@ MozInputMethod.prototype = {
_inputcontext: null,
_wrappedInputContext: null,
_layouts: {},
_supportsSwitchingTypes: [],
_window: null,
classID: Components.ID("{4607330d-e7d2-40a4-9eb8-43967eae0142}"),
@ -208,7 +214,7 @@ MozInputMethod.prototype = {
cpmm.addWeakMessageListener('Keyboard:Blur', this);
cpmm.addWeakMessageListener('Keyboard:SelectionChange', this);
cpmm.addWeakMessageListener('Keyboard:GetContext:Result:OK', this);
cpmm.addWeakMessageListener('Keyboard:LayoutsChange', this);
cpmm.addWeakMessageListener('Keyboard:SupportsSwitchingTypesChange', this);
cpmm.addWeakMessageListener('InputRegistry:Result:OK', this);
cpmm.addWeakMessageListener('InputRegistry:Result:Error', this);
},
@ -221,7 +227,7 @@ MozInputMethod.prototype = {
cpmm.removeWeakMessageListener('Keyboard:Blur', this);
cpmm.removeWeakMessageListener('Keyboard:SelectionChange', this);
cpmm.removeWeakMessageListener('Keyboard:GetContext:Result:OK', this);
cpmm.removeWeakMessageListener('Keyboard:LayoutsChange', this);
cpmm.removeWeakMessageListener('Keyboard:SupportsSwitchingTypesChange', this);
cpmm.removeWeakMessageListener('InputRegistry:Result:OK', this);
cpmm.removeWeakMessageListener('InputRegistry:Result:Error', this);
this.setActive(false);
@ -253,8 +259,8 @@ MozInputMethod.prototype = {
case 'Keyboard:GetContext:Result:OK':
this.setInputContext(data);
break;
case 'Keyboard:LayoutsChange':
this._layouts = data;
case 'Keyboard:SupportsSwitchingTypesChange':
this._supportsSwitchingTypes = data.types;
break;
case 'InputRegistry:Result:OK':
@ -299,13 +305,12 @@ MozInputMethod.prototype = {
this._inputcontext.destroy();
this._inputcontext = null;
this._wrappedInputContext = null;
this._mgmt._supportsSwitching = false;
this._mgmt.supportsSwitchingForCurrentInputContext = false;
}
if (data) {
this._mgmt._supportsSwitching = this._layouts[data.inputType] ?
this._layouts[data.inputType] > 1 :
false;
this._mgmt.supportsSwitchingForCurrentInputContext =
(this._supportsSwitchingTypes.indexOf(data.inputType) !== -1);
this._inputcontext = new MozInputContext(data);
this._inputcontext.init(this._window);

Просмотреть файл

@ -21,9 +21,10 @@ support-files =
[test_bug1059163.html]
[test_bug1066515.html]
[test_bug1175399.html]
[test_bug1137557.html]
[test_sendkey_cancel.html]
[test_setSupportsSwitching.html]
[test_sync_edit.html]
[test_two_inputs.html]
[test_two_selects.html]
[test_unload.html]
[test_bug1137557.html]

Просмотреть файл

@ -0,0 +1,134 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1197682
-->
<head>
<title>Test inputcontext#inputType and MozInputMethodManager#supportsSwitching()</title>
<script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript;version=1.7" src="inputmethod_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1197682">Mozilla Bug 1197682</a>
<p id="display"></p>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
inputmethod_setup(function() {
runTest();
});
let appFrameScript = function appFrameScript() {
let input = content.document.body.firstElementChild;
let i = 1;
input.focus();
addMessageListener('test:next', function() {
i++;
switch (i) {
case 2:
content.document.body.children[1].focus();
i++; // keep the same count with the parent frame.
break;
case 4:
content.document.body.lastElementChild.focus();
i++; // keep the same count with the parent frame.
break;
case 6:
content.document.body.lastElementChild.blur();
break;
}
});
};
function runTest() {
let im = navigator.mozInputMethod;
let i = 0;
im.oninputcontextchange = function(evt) {
var inputcontext = navigator.mozInputMethod.inputcontext;
i++;
switch (i) {
case 1:
ok(!!inputcontext, '1) Receving the input context');
is(inputcontext.inputType, 'text', '1) input type');
is(im.mgmt.supportsSwitching(), true, '1) supports switching');
mm.sendAsyncMessage('test:next');
break;
case 2:
is(inputcontext, null, '2) Receving null inputcontext');
break;
case 3:
ok(!!inputcontext, '3) Receving the input context');
is(inputcontext.inputType, 'number', '3) input type');
is(im.mgmt.supportsSwitching(), false, '3) supports switching');
mm.sendAsyncMessage('test:next');
break;
case 4:
is(inputcontext, null, '4) Receving null inputcontext');
break;
case 5:
ok(!!inputcontext, '5) Receving the input context');
is(inputcontext.inputType, 'password', '5) input type');
is(im.mgmt.supportsSwitching(), true, '5) supports switching');
mm.sendAsyncMessage('test:next');
break;
case 6:
is(inputcontext, null, '6) Receving null inputcontext');
is(im.mgmt.supportsSwitching(), false, '6) supports switching');
inputmethod_cleanup();
break;
default:
ok(false, 'Receving extra inputcontextchange calls');
inputmethod_cleanup();
break;
}
};
// Set current page as an input method.
SpecialPowers.wrap(im).setActive(true);
// Set text and password inputs as supports switching (and not supported for number type)
im.mgmt.setSupportsSwitchingTypes(['text', 'password']);
let iframe = document.createElement('iframe');
iframe.src = 'data:text/html,<html><body>' +
'<input type="text">' +
'<input type="number">' +
'<input type="password">' +
'</body></html>';
iframe.setAttribute('mozbrowser', true);
document.body.appendChild(iframe);
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
iframe.addEventListener('mozbrowserloadend', function() {
mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
});
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -119,13 +119,14 @@ interface MozInputMethod : EventTarget {
*/
[JSImplementation="@mozilla.org/b2g-imm;1",
Pref="dom.mozInputMethod.enabled",
CheckAnyPermissions="input"]
CheckAnyPermissions="input input-manage"]
interface MozInputMethodManager {
/**
* Ask the OS to show a list of available inputs for users to switch from.
* OS should sliently ignore this request if the app is currently not the
* active one.
*/
[CheckAllPermissions="input"]
void showAll();
/**
@ -133,16 +134,18 @@ interface MozInputMethodManager {
* OS should sliently ignore this request if the app is currently not the
* active one.
*/
[CheckAllPermissions="input"]
void next();
/**
* If this method returns true, it is recommented that the input app provides
* If this method returns true, it is recommended that the input app provides
* a shortcut that would invoke the next() method above, for easy switching
* between inputs -- i.e. show a "global" button on screen if the input app
* implements an on-screen virtual keyboard.
*
* The returning value is depend on the inputType of the current input context.
*/
[CheckAllPermissions="input"]
boolean supportsSwitching();
/**
@ -150,7 +153,18 @@ interface MozInputMethodManager {
* OS should sliently ignore this request if the app is currently not the
* active one.
*/
[CheckAllPermissions="input"]
void hide();
/**
* Update Gecko with information on the input types which supportsSwitching()
* should return ture.
*
* @param types Array of input types in which supportsSwitching() should
* return true.
*/
[CheckAllPermissions="input-manage"]
void setSupportsSwitchingTypes(sequence<MozInputMethodInputContextInputTypes> types);
};
/**