diff --git a/dom/inputmethod/Keyboard.jsm b/dom/inputmethod/Keyboard.jsm index ef2014cc6c06..322d55256873 100644 --- a/dom/inputmethod/Keyboard.jsm +++ b/dom/inputmethod/Keyboard.jsm @@ -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 + }); } }; diff --git a/dom/inputmethod/MozKeyboard.js b/dom/inputmethod/MozKeyboard.js index 5339308d4c7c..32d1d93c109f 100644 --- a/dom/inputmethod/MozKeyboard.js +++ b/dom/inputmethod/MozKeyboard.js @@ -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); diff --git a/dom/inputmethod/mochitest/mochitest.ini b/dom/inputmethod/mochitest/mochitest.ini index ab39bfdeb7f3..3c2614e67fbd 100644 --- a/dom/inputmethod/mochitest/mochitest.ini +++ b/dom/inputmethod/mochitest/mochitest.ini @@ -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] diff --git a/dom/inputmethod/mochitest/test_setSupportsSwitching.html b/dom/inputmethod/mochitest/test_setSupportsSwitching.html new file mode 100644 index 000000000000..b03e88fefb28 --- /dev/null +++ b/dom/inputmethod/mochitest/test_setSupportsSwitching.html @@ -0,0 +1,134 @@ + + + + + Test inputcontext#inputType and MozInputMethodManager#supportsSwitching() + + + + + +Mozilla Bug 1197682 +

+
+
+
+ + diff --git a/dom/webidl/InputMethod.webidl b/dom/webidl/InputMethod.webidl index bf2671c4eced..46e5963eb7a0 100644 --- a/dom/webidl/InputMethod.webidl +++ b/dom/webidl/InputMethod.webidl @@ -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 types); }; /**