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
) {
23 * @type {remoting.ContextMenuAdapter}
26 this.adapter_
= adapter
;
28 * @type {remoting.SubmenuManager}
31 this.submenuManager_
= new remoting
.SubmenuManager(
33 chrome
.i18n
.getMessage(/*i18n-content*/'KEYBOARD_LAYOUTS_SUBMENU_TITLE'),
39 this.currentLayout_
= '';
41 adapter
.addListener(this.onContextMenu_
.bind(this));
45 * @param {Array<string>} layouts The keyboard layouts available on the host,
46 * for example en-US, de-DE
47 * @param {string} currentLayout The layout currently active on the host.
49 remoting
.KeyboardLayoutsMenu
.prototype.setLayouts
=
50 function(layouts
, currentLayout
) {
51 this.submenuManager_
.removeAll();
52 this.currentLayout_
= '';
53 for (var i
= 0; i
< layouts
.length
; ++i
) {
54 this.submenuManager_
.add(this.makeMenuId_(layouts
[i
]), layouts
[i
]);
56 // Pick a suitable default layout.
57 this.getBestLayout_(layouts
, currentLayout
,
58 this.setLayout_
.bind(this, false));
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 remoting
.clientSession
.sendClientMessage(
81 JSON
.stringify({layout
: layout
}));
82 if (saveToLocalStorage
) {
84 params
[remoting
.KeyboardLayoutsMenu
.KEY_
] = layout
;
85 chrome
.storage
.local
.set(params
);
90 * Choose the best keyboard from the alternatives, based on the following
92 * - Search local storage by for a preferred keyboard layout for the app;
93 * if it is found, prefer it over the current locale, falling back on the
94 * latter only if no match is found.
95 * - If the candidate layout matches one of the supported layouts, use it.
96 * - Otherwise, if the language portion of the candidate matches that of
97 * any of the supported layouts, use the first such layout (e.g, en-AU
98 * will match either en-US or en-GB, whichever appears first).
99 * - Otherwise, use the host's current layout.
101 * @param {Array<string>} layouts
102 * @param {string} currentHostLayout
103 * @param {function(string):void} onDone
106 remoting
.KeyboardLayoutsMenu
.prototype.getBestLayout_
=
107 function(layouts
, currentHostLayout
, onDone
) {
109 * Extract the language id from a string that is either "language" (e.g.
110 * "de") or "language-region" (e.g. "en-US").
112 * @param {string} layout
115 var getLanguage = function(layout
) {
116 var languageAndRegion
= layout
.split('-');
117 switch (languageAndRegion
.length
) {
120 return languageAndRegion
[0];
126 /** @param {Object<string>} storage */
127 var chooseLayout = function(storage
) {
128 var configuredLayout
= storage
[remoting
.KeyboardLayoutsMenu
.KEY_
];
129 var tryLayouts
= [ chrome
.i18n
.getUILanguage() ];
130 if (configuredLayout
&& typeof(configuredLayout
) == 'string') {
131 tryLayouts
.unshift(configuredLayout
);
133 for (var i
= 0; i
< tryLayouts
.length
; ++i
) {
134 if (layouts
.indexOf(tryLayouts
[i
]) != -1) {
135 onDone(tryLayouts
[i
]);
138 var language
= getLanguage(tryLayouts
[i
]);
140 for (var j
= 0; j
< layouts
.length
; ++j
) {
141 if (language
== getLanguage(layouts
[j
])) {
148 // Neither the stored layout nor UI locale was suitable.
149 onDone(currentHostLayout
);
152 chrome
.storage
.local
.get(remoting
.KeyboardLayoutsMenu
.KEY_
, chooseLayout
);
156 * Create a menu id from the given keyboard layout.
158 * @param {string} layout Keyboard layout
162 remoting
.KeyboardLayoutsMenu
.prototype.makeMenuId_ = function(layout
) {
163 return 'layout@' + layout
;
167 * Handle a click on the application's context menu.
169 * @param {OnClickData=} info
172 remoting
.KeyboardLayoutsMenu
.prototype.onContextMenu_ = function(info
) {
173 /** @type {Array<string>} */
174 var components
= info
.menuItemId
.split('@');
175 if (components
.length
== 2 &&
176 this.makeMenuId_(components
[1]) == info
.menuItemId
) {
177 this.setLayout_(true, components
[1]);
185 remoting
.KeyboardLayoutsMenu
.KEY_
= 'preferred-keyboard-layout';