OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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. | |
4 | |
5 /** | |
6 * @fileoverview A simple virtual keyboard implementation. | |
7 */ | |
8 | |
9 /** | |
10 * The ratio of the row height to the font size. | |
11 * @type {number} | |
12 */ | |
13 const kFontSizeRatio = 3.5; | |
14 | |
15 /** | |
16 * Return the id attribute of the keyboard element for the given layout. | |
17 * @param {string} layout The keyboard layout. | |
18 * @return {string} The id attribute of the keyboard element. | |
19 */ | |
20 function getKeyboardId(layout) { | |
21 return 'keyboard_' + layout; | |
22 } | |
23 | |
24 /** | |
25 * Return the aspect ratio of the current keyboard. | |
26 * @param {string} layout The keyboard layout. | |
27 * @return {number} The aspect ratio of the current keyboard. | |
28 */ | |
29 function getKeyboardAspect() { | |
30 return KEYBOARDS[currentKeyboardLayout]['aspect']; | |
31 } | |
32 | |
33 /** | |
34 * Calculate the height of the keyboard based on the size of the page. | |
35 * @return {number} The height of the keyboard in pixels. | |
36 */ | |
37 function getKeyboardHeight() { | |
38 var x = window.innerWidth; | |
39 var y = window.innerHeight - ((imeui && imeui.visible) ? IME_HEIGHT : 0); | |
40 return (x > getKeyboardAspect() * y) ? | |
41 y : Math.floor(x / getKeyboardAspect()); | |
42 } | |
43 | |
44 /** | |
45 * Create a DOM of the keyboard rows for the given keyboard layout. | |
46 * Do nothing if the DOM is already created. | |
47 * @param {string} layout The keyboard layout for which rows are created. | |
48 * @param {Element} element The DOM Element to which rows are appended. | |
49 * @param {boolean} autoPadding True if padding needs to be added to both side | |
50 * of the rows that have less keys. | |
51 * @return {void} | |
52 */ | |
53 function initRows(layout, element, autoPadding) { | |
54 var keyboard = KEYBOARDS[layout]; | |
55 if ('rows' in keyboard) { | |
56 return; | |
57 } | |
58 var def = keyboard['definition']; | |
59 var rows = []; | |
60 for (var i = 0; i < def.length; ++i) { | |
61 rows.push(new Row(i, def[i])); | |
62 } | |
63 keyboard['rows'] = rows; | |
64 | |
65 var maxRowLength = -1; | |
66 for (var i = 0; i < rows.length; ++i) { | |
67 if (rows[i].length > maxRowLength) { | |
68 maxRowLength = rows[i].length; | |
69 } | |
70 } | |
71 | |
72 // A div element which holds rows for the layout. | |
73 var rowsDiv = document.createElement('div'); | |
74 rowsDiv.className = 'rows'; | |
75 for (var i = 0; i < rows.length; ++i) { | |
76 var rowDiv = rows[i].makeDOM(); | |
77 if (autoPadding && rows[i].length < maxRowLength) { | |
78 var padding = 50 * (maxRowLength - rows[i].length) / maxRowLength; | |
79 rowDiv.style.paddingLeft = padding + '%'; | |
80 rowDiv.style.paddingRight = padding + '%'; | |
81 } | |
82 rowsDiv.appendChild(rowDiv); | |
83 rows[i].showMode(currentMode); | |
84 } | |
85 keyboard['rowsDiv'] = rowsDiv; | |
86 element.appendChild(rowsDiv); | |
87 } | |
88 | |
89 /** | |
90 * Create a DOM of the handwriting canvas for the given keyboard layout. | |
91 * Do nothing if the DOM is already created or the layout doesn't have canvas. | |
92 * @param {string} layout The keyboard layout for which canvas is created. | |
93 * @param {Element} The DOM Element to which canvas is appended. | |
94 * @return {void} | |
95 */ | |
96 function initHandwritingCanvas(layout, element) { | |
97 var keyboard = KEYBOARDS[layout]; | |
98 if (!('canvas' in keyboard) || keyboard['canvas']) { | |
99 return; | |
100 } | |
101 var canvas = new HandwritingCanvas(); | |
102 canvas.className = 'handwritingcanvas'; | |
103 var border = 1; | |
104 var marginTop = 5; | |
105 var canvasHeight = getKeyboardHeight() - 2 * border - marginTop; | |
106 canvas.resize(canvasHeight); | |
107 keyboard['canvas'] = canvas; | |
108 element.appendChild(canvas); | |
109 } | |
110 | |
111 /** | |
112 * Create a DOM of the keyboard for the given keyboard layout. | |
113 * Do nothing if the DOM is already created. | |
114 * @param {string} layout The keyboard layout for which keyboard is created. | |
115 * @param {Element} The DOM Element to which keyboard is appended. | |
116 * @return {void} | |
117 */ | |
118 function initKeyboard(layout, element) { | |
119 var keyboard = KEYBOARDS[layout]; | |
120 if (!keyboard || keyboard['keyboardDiv']) { | |
121 return; | |
122 } | |
123 var keyboardDiv = document.createElement('div'); | |
124 keyboardDiv.id = getKeyboardId(layout); | |
125 keyboardDiv.className = 'keyboard'; | |
126 initRows(layout, keyboardDiv); | |
127 initHandwritingCanvas(layout, keyboardDiv); | |
128 keyboard['keyboardDiv'] = keyboardDiv; | |
129 window.onresize(); | |
130 element.appendChild(keyboardDiv); | |
131 } | |
132 | |
133 /** | |
134 * Create a DOM of the popup keyboard. | |
135 * @param {Element} The DOM Element to which the popup keyboard is appended. | |
136 * @return {void} | |
137 */ | |
138 function initPopupKeyboard(element) { | |
139 var popupDiv = document.createElement('div'); | |
140 popupDiv.id = 'popup'; | |
141 popupDiv.className = 'keyboard popup'; | |
142 popupDiv.style.visibility = 'hidden'; | |
143 element.appendChild(popupDiv); | |
144 element.addEventListener('mouseup', function(evt) { | |
145 hidePopupKeyboard(evt); | |
146 }); | |
147 } | |
148 | |
149 /** | |
150 * Resize the keyboard according to the new window size. | |
151 * @return {void} | |
152 */ | |
153 window.onresize = function() { | |
154 var keyboardDiv = KEYBOARDS[currentKeyboardLayout]['keyboardDiv']; | |
155 var height = getKeyboardHeight(); | |
156 keyboardDiv.style.height = height + 'px'; | |
157 var mainDiv = document.getElementById('main'); | |
158 mainDiv.style.width = Math.floor(getKeyboardAspect() * height) + 'px'; | |
159 var rowsLength = KEYBOARDS[currentKeyboardLayout]['rows'].length; | |
160 keyboardDiv.style.fontSize = (height / kFontSizeRatio / rowsLength) + 'px'; | |
161 updateIme(); | |
162 } | |
163 | |
164 /** | |
165 * Init the keyboard. | |
166 * @return {void} | |
167 */ | |
168 window.onload = function() { | |
169 var body = document.getElementById('b'); | |
170 | |
171 // Catch all unhandled touch events and prevent default, to prevent the | |
172 // keyboard from responding to gestures like double tap. | |
173 function disableGestures(evt) { | |
174 evt.preventDefault(); | |
175 } | |
176 body.addEventListener('touchstart', disableGestures); | |
177 body.addEventListener('touchmove', disableGestures); | |
178 body.addEventListener('touchend', disableGestures); | |
179 | |
180 var mainDiv = document.createElement('div'); | |
181 mainDiv.className = 'main'; | |
182 mainDiv.id = 'main'; | |
183 body.appendChild(mainDiv); | |
184 | |
185 initIme(mainDiv); | |
186 initKeyboard(currentKeyboardLayout, mainDiv); | |
187 initPopupKeyboard(body); | |
188 | |
189 window.onhashchange(); | |
190 | |
191 chrome.experimental.input.virtualKeyboard.onTextInputTypeChanged.addListener( | |
192 function(type) { | |
193 var newMode = SHIFT_MODE; | |
194 switch(type) { | |
195 case "text": | |
196 newMode = SHIFT_MODE; | |
197 break; | |
198 case "email": | |
199 case "password": | |
200 case "search": | |
201 case "url": | |
202 newMode = KEY_MODE; | |
203 break; | |
204 case "number": | |
205 case "tel": | |
206 newMode = NUMBER_MODE; | |
207 break; | |
208 default: | |
209 newMode = KEY_MODE; | |
210 break; | |
211 } | |
212 setMode(newMode); | |
213 }); | |
214 } | |
215 // TODO(bryeung): would be nice to leave less gutter (without causing | |
216 // rendering issues with floated divs wrapping at some sizes). | |
217 | |
218 /** | |
219 * Switch the keyboard layout based on the current URL hash. | |
220 * @return {void} | |
221 */ | |
222 window.onhashchange = function() { | |
223 var old_layout = currentKeyboardLayout; | |
224 var new_layout = location.hash.replace(/^#/, ""); | |
225 if (old_layout == new_layout) { | |
226 return; | |
227 } | |
228 | |
229 if (KEYBOARDS[new_layout] === undefined) { | |
230 // Unsupported layout. | |
231 new_layout = "us"; | |
232 } | |
233 currentKeyboardLayout = new_layout; | |
234 | |
235 var mainDiv = document.getElementById('main'); | |
236 initKeyboard(currentKeyboardLayout, mainDiv); | |
237 | |
238 [new_layout, old_layout].forEach(function(layout) { | |
239 var visible = (layout == new_layout); | |
240 var keyboardDiv = KEYBOARDS[layout]['keyboardDiv']; | |
241 keyboardDiv.className = visible ? 'keyboard' : 'nodisplay'; | |
242 var canvas = KEYBOARDS[layout]['canvas']; | |
243 if (canvas !== undefined) { | |
244 if (!visible) { | |
245 canvas.clear(); | |
246 } | |
247 } | |
248 if (visible) { | |
249 window.onresize(); | |
250 } | |
251 }); | |
252 } | |
OLD | NEW |