1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 * Class managing the host's available keyboard layouts, allowing the user to
8 * select one that matches the local layout, or auto-selecting based on the
14 /** @suppress {duplicate} */
15 var remoting
= remoting
|| {};
18 * @param {remoting.ContextMenuAdapter} adapter
21 remoting
.KeyboardLayoutsMenu = function(adapter
) {
22 /** @private {remoting.ContextMenuAdapter} */
23 this.adapter_
= adapter
;
24 /** @private {remoting.SubmenuManager} */
25 this.submenuManager_
= new remoting
.SubmenuManager(
27 chrome
.i18n
.getMessage(/*i18n-content*/'KEYBOARD_LAYOUTS_SUBMENU_TITLE'),
29 /** @private {string} */
30 this.currentLayout_
= '';
32 /** @private {function(string, string)} */
33 this.sendExtensionMessage_
= base
.doNothing
;
35 adapter
.addListener(this.onContextMenu_
.bind(this));
39 * @param {Array<string>} layouts The keyboard layouts available on the host,
40 * for example en-US, de-DE
41 * @param {string} currentLayout The layout currently active on the host.
43 remoting
.KeyboardLayoutsMenu
.prototype.setLayouts
=
44 function(layouts
, currentLayout
) {
45 this.submenuManager_
.removeAll();
46 this.currentLayout_
= '';
47 for (var i
= 0; i
< layouts
.length
; ++i
) {
48 this.submenuManager_
.add(this.makeMenuId_(layouts
[i
]), layouts
[i
]);
50 // Pick a suitable default layout.
51 this.getBestLayout_(layouts
, currentLayout
,
52 this.setLayout_
.bind(this, false));
55 /** @param {function(string, string)} callback */
56 remoting
.KeyboardLayoutsMenu
.prototype.setExtensionMessageSender
=
58 this.sendExtensionMessage_
= callback
;
62 * Notify the host that a new keyboard layout has been selected.
64 * @param {boolean} saveToLocalStorage If true, save the specified layout to
66 * @param {string} layout The new keyboard layout.
69 remoting
.KeyboardLayoutsMenu
.prototype.setLayout_
=
70 function(saveToLocalStorage
, layout
) {
71 if (this.currentLayout_
!= '') {
72 this.adapter_
.updateCheckState(
73 this.makeMenuId_(this.currentLayout_
), false);
75 this.adapter_
.updateCheckState(this.makeMenuId_(layout
), true);
76 this.currentLayout_
= layout
;
78 console
.log("Setting the keyboard layout to '" + layout
+ "'");
79 this.sendExtensionMessage_('setKeyboardLayout',
80 JSON
.stringify({layout
: layout
}));
81 if (saveToLocalStorage
) {
83 params
[remoting
.KeyboardLayoutsMenu
.KEY_
] = layout
;
84 chrome
.storage
.local
.set(params
);
89 * Choose the best keyboard from the alternatives, based on the following
91 * - Search local storage by for a preferred keyboard layout for the app;
92 * if it is found, prefer it over the current locale, falling back on the
93 * latter only if no match is found.
94 * - If the candidate layout matches one of the supported layouts, use it.
95 * - Otherwise, if the language portion of the candidate matches that of
96 * any of the supported layouts, use the first such layout (e.g, en-AU
97 * will match either en-US or en-GB, whichever appears first).
98 * - Otherwise, use the host's current layout.
100 * @param {Array<string>} layouts
101 * @param {string} currentHostLayout
102 * @param {function(string):void} onDone
105 remoting
.KeyboardLayoutsMenu
.prototype.getBestLayout_
=
106 function(layouts
, currentHostLayout
, onDone
) {
108 * Extract the language id from a string that is either "language" (e.g.
109 * "de") or "language-region" (e.g. "en-US").
111 * @param {string} layout
114 var getLanguage = function(layout
) {
115 var languageAndRegion
= layout
.split('-');
116 switch (languageAndRegion
.length
) {
119 return languageAndRegion
[0];
125 /** @param {Object<string>} storage */
126 var chooseLayout = function(storage
) {
127 var configuredLayout
= storage
[remoting
.KeyboardLayoutsMenu
.KEY_
];
128 var tryLayouts
= [ chrome
.i18n
.getUILanguage() ];
129 if (configuredLayout
&& typeof(configuredLayout
) == 'string') {
130 tryLayouts
.unshift(configuredLayout
);
132 for (var i
= 0; i
< tryLayouts
.length
; ++i
) {
133 if (layouts
.indexOf(tryLayouts
[i
]) != -1) {
134 onDone(tryLayouts
[i
]);
137 var language
= getLanguage(tryLayouts
[i
]);
139 for (var j
= 0; j
< layouts
.length
; ++j
) {
140 if (language
== getLanguage(layouts
[j
])) {
147 // Neither the stored layout nor UI locale was suitable.
148 onDone(currentHostLayout
);
151 chrome
.storage
.local
.get(remoting
.KeyboardLayoutsMenu
.KEY_
, chooseLayout
);
155 * Create a menu id from the given keyboard layout.
157 * @param {string} layout Keyboard layout
161 remoting
.KeyboardLayoutsMenu
.prototype.makeMenuId_ = function(layout
) {
162 return 'layout@' + layout
;
166 * Handle a click on the application's context menu.
168 * @param {OnClickData=} info
171 remoting
.KeyboardLayoutsMenu
.prototype.onContextMenu_ = function(info
) {
172 var menuItemId
= info
.menuItemId
.toString();
173 var components
= menuItemId
.split('@');
174 if (components
.length
== 2 &&
175 this.makeMenuId_(components
[1]) === menuItemId
) {
176 this.setLayout_(true, components
[1]);
184 remoting
.KeyboardLayoutsMenu
.KEY_
= 'preferred-keyboard-layout';