Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ui / keyboard / keyboard_util.cc
1 // Copyright (c) 2013 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 #include "ui/keyboard/keyboard_util.h"
6
7 #include <string>
8
9 #include "base/command_line.h"
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "base/metrics/histogram.h"
13 #include "base/strings/string16.h"
14 #include "grit/keyboard_resources.h"
15 #include "grit/keyboard_resources_map.h"
16 #include "ui/aura/client/aura_constants.h"
17 #include "ui/aura/window_tree_host.h"
18 #include "ui/base/ime/input_method.h"
19 #include "ui/base/ime/text_input_client.h"
20 #include "ui/events/event_processor.h"
21 #include "ui/keyboard/keyboard_switches.h"
22 #include "url/gurl.h"
23
24 namespace {
25
26 const char kKeyDown[] ="keydown";
27 const char kKeyUp[] = "keyup";
28
29 void SendProcessKeyEvent(ui::EventType type,
30                          aura::WindowTreeHost* host) {
31   ui::KeyEvent event(type, ui::VKEY_PROCESSKEY, ui::EF_NONE);
32   event.SetTranslated(true);
33   ui::EventDispatchDetails details =
34       host->event_processor()->OnEventFromSource(&event);
35   CHECK(!details.dispatcher_destroyed);
36 }
37
38 base::LazyInstance<base::Time> g_keyboard_load_time_start =
39     LAZY_INSTANCE_INITIALIZER;
40
41 bool g_accessibility_keyboard_enabled = false;
42
43 base::LazyInstance<GURL> g_override_content_url = LAZY_INSTANCE_INITIALIZER;
44
45 bool g_touch_keyboard_enabled = false;
46
47 keyboard::KeyboardOverscrolOverride g_keyboard_overscroll_override =
48     keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_NONE;
49
50 keyboard::KeyboardShowOverride g_keyboard_show_override =
51     keyboard::KEYBOARD_SHOW_OVERRIDE_NONE;
52
53 }  // namespace
54
55 namespace keyboard {
56
57 gfx::Rect DefaultKeyboardBoundsFromWindowBounds(
58     const gfx::Rect& window_bounds) {
59   // Initialize default keyboard height to 0. The keyboard window height should
60   // only be set by window.resizeTo in virtual keyboard web contents. Otherwise,
61   // the default height may conflict with the new height and causing some
62   // strange animation issues.
63   return KeyboardBoundsFromWindowBounds(window_bounds, 0);
64 }
65
66 gfx::Rect KeyboardBoundsFromWindowBounds(const gfx::Rect& window_bounds,
67                                          int keyboard_height) {
68   return gfx::Rect(
69       window_bounds.x(),
70       window_bounds.bottom() - keyboard_height,
71       window_bounds.width(),
72       keyboard_height);
73 }
74
75 void SetAccessibilityKeyboardEnabled(bool enabled) {
76   g_accessibility_keyboard_enabled = enabled;
77 }
78
79 bool GetAccessibilityKeyboardEnabled() {
80   return g_accessibility_keyboard_enabled;
81 }
82
83 void SetTouchKeyboardEnabled(bool enabled) {
84   g_touch_keyboard_enabled = enabled;
85 }
86
87 bool GetTouchKeyboardEnabled() {
88   return g_touch_keyboard_enabled;
89 }
90
91 std::string GetKeyboardLayout() {
92   // TODO(bshe): layout string is currently hard coded. We should use more
93   // standard keyboard layouts.
94   return GetAccessibilityKeyboardEnabled() ? "system-qwerty" : "qwerty";
95 }
96
97 bool IsKeyboardEnabled() {
98   // Accessibility setting prioritized over policy setting.
99   if (g_accessibility_keyboard_enabled)
100     return true;
101   // Policy strictly disables showing a virtual keyboard.
102   if (g_keyboard_show_override == keyboard::KEYBOARD_SHOW_OVERRIDE_DISABLED)
103     return false;
104   // Check if any of the flags are enabled.
105   return CommandLine::ForCurrentProcess()->HasSwitch(
106              switches::kEnableVirtualKeyboard) ||
107          g_touch_keyboard_enabled ||
108          (g_keyboard_show_override == keyboard::KEYBOARD_SHOW_OVERRIDE_ENABLED);
109 }
110
111 bool IsKeyboardOverscrollEnabled() {
112   if (!IsKeyboardEnabled())
113     return false;
114
115   // Users of the accessibility on-screen keyboard are likely to be using mouse
116   // input, which may interfere with overscrolling.
117   if (g_accessibility_keyboard_enabled)
118     return false;
119
120   // If overscroll enabled override is set, use it instead. Currently
121   // login / out-of-box disable keyboard overscroll. http://crbug.com/363635
122   if (g_keyboard_overscroll_override != KEYBOARD_OVERSCROLL_OVERRIDE_NONE) {
123     return g_keyboard_overscroll_override ==
124         KEYBOARD_OVERSCROLL_OVERRIDE_ENABLED;
125   }
126
127   if (CommandLine::ForCurrentProcess()->HasSwitch(
128       switches::kDisableVirtualKeyboardOverscroll)) {
129     return false;
130   }
131   return true;
132 }
133
134 void SetKeyboardOverscrollOverride(KeyboardOverscrolOverride override) {
135   g_keyboard_overscroll_override = override;
136 }
137
138 void SetKeyboardShowOverride(KeyboardShowOverride override) {
139   g_keyboard_show_override = override;
140 }
141
142 bool IsInputViewEnabled() {
143   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableInputView))
144     return true;
145   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableInputView))
146     return false;
147   // Default value if no command line flags specified.
148   return true;
149 }
150
151 bool IsExperimentalInputViewEnabled() {
152   if (CommandLine::ForCurrentProcess()->HasSwitch(
153       switches::kEnableExperimentalInputViewFeatures)) {
154     return true;
155   }
156   return false;
157 }
158
159 bool InsertText(const base::string16& text, aura::Window* root_window) {
160   if (!root_window)
161     return false;
162
163   ui::InputMethod* input_method = root_window->GetProperty(
164       aura::client::kRootWindowInputMethodKey);
165   if (!input_method)
166     return false;
167
168   ui::TextInputClient* tic = input_method->GetTextInputClient();
169   if (!tic || tic->GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
170     return false;
171
172   tic->InsertText(text);
173
174   return true;
175 }
176
177 // TODO(varunjain): It would be cleaner to have something in the
178 // ui::TextInputClient interface, say MoveCaretInDirection(). The code in
179 // here would get the ui::InputMethod from the root_window, and the
180 // ui::TextInputClient from that (see above in InsertText()).
181 bool MoveCursor(int swipe_direction,
182                 int modifier_flags,
183                 aura::WindowTreeHost* host) {
184   if (!host)
185     return false;
186   ui::KeyboardCode codex = ui::VKEY_UNKNOWN;
187   ui::KeyboardCode codey = ui::VKEY_UNKNOWN;
188   if (swipe_direction & kCursorMoveRight)
189     codex = ui::VKEY_RIGHT;
190   else if (swipe_direction & kCursorMoveLeft)
191     codex = ui::VKEY_LEFT;
192
193   if (swipe_direction & kCursorMoveUp)
194     codey = ui::VKEY_UP;
195   else if (swipe_direction & kCursorMoveDown)
196     codey = ui::VKEY_DOWN;
197
198   // First deal with the x movement.
199   if (codex != ui::VKEY_UNKNOWN) {
200     ui::KeyEvent press_event(ui::ET_KEY_PRESSED, codex, modifier_flags);
201     ui::EventDispatchDetails details =
202         host->event_processor()->OnEventFromSource(&press_event);
203     CHECK(!details.dispatcher_destroyed);
204     ui::KeyEvent release_event(ui::ET_KEY_RELEASED, codex, modifier_flags);
205     details = host->event_processor()->OnEventFromSource(&release_event);
206     CHECK(!details.dispatcher_destroyed);
207   }
208
209   // Then deal with the y movement.
210   if (codey != ui::VKEY_UNKNOWN) {
211     ui::KeyEvent press_event(ui::ET_KEY_PRESSED, codey, modifier_flags);
212     ui::EventDispatchDetails details =
213         host->event_processor()->OnEventFromSource(&press_event);
214     CHECK(!details.dispatcher_destroyed);
215     ui::KeyEvent release_event(ui::ET_KEY_RELEASED, codey, modifier_flags);
216     details = host->event_processor()->OnEventFromSource(&release_event);
217     CHECK(!details.dispatcher_destroyed);
218   }
219   return true;
220 }
221
222 bool SendKeyEvent(const std::string type,
223                   int key_value,
224                   int key_code,
225                   std::string key_name,
226                   int modifiers,
227                   aura::WindowTreeHost* host) {
228   ui::EventType event_type = ui::ET_UNKNOWN;
229   if (type == kKeyDown)
230     event_type = ui::ET_KEY_PRESSED;
231   else if (type == kKeyUp)
232     event_type = ui::ET_KEY_RELEASED;
233   if (event_type == ui::ET_UNKNOWN)
234     return false;
235
236   ui::KeyboardCode code = static_cast<ui::KeyboardCode>(key_code);
237
238   if (code == ui::VKEY_UNKNOWN) {
239     // Handling of special printable characters (e.g. accented characters) for
240     // which there is no key code.
241     if (event_type == ui::ET_KEY_RELEASED) {
242       ui::InputMethod* input_method = host->window()->GetProperty(
243           aura::client::kRootWindowInputMethodKey);
244       if (!input_method)
245         return false;
246
247       ui::TextInputClient* tic = input_method->GetTextInputClient();
248
249       SendProcessKeyEvent(ui::ET_KEY_PRESSED, host);
250       tic->InsertChar(static_cast<uint16>(key_value), ui::EF_NONE);
251       SendProcessKeyEvent(ui::ET_KEY_RELEASED, host);
252     }
253   } else {
254     if (event_type == ui::ET_KEY_RELEASED) {
255       // The number of key press events seen since the last backspace.
256       static int keys_seen = 0;
257       if (code == ui::VKEY_BACK) {
258         // Log the rough lengths of characters typed between backspaces. This
259         // metric will be used to determine the error rate for the keyboard.
260         UMA_HISTOGRAM_CUSTOM_COUNTS(
261             "VirtualKeyboard.KeystrokesBetweenBackspaces",
262             keys_seen, 1, 1000, 50);
263         keys_seen = 0;
264       } else {
265         ++keys_seen;
266       }
267     }
268
269     ui::KeyEvent event(event_type, code, key_name, modifiers);
270     ui::EventDispatchDetails details =
271         host->event_processor()->OnEventFromSource(&event);
272     CHECK(!details.dispatcher_destroyed);
273   }
274   return true;
275 }
276
277 void MarkKeyboardLoadStarted() {
278   if (!g_keyboard_load_time_start.Get().ToInternalValue())
279     g_keyboard_load_time_start.Get() = base::Time::Now();
280 }
281
282 void MarkKeyboardLoadFinished() {
283   // Possible to get a load finished without a start if navigating directly to
284   // chrome://keyboard.
285   if (!g_keyboard_load_time_start.Get().ToInternalValue())
286     return;
287
288   // It should not be possible to finish loading the keyboard without starting
289   // to load it first.
290   DCHECK(g_keyboard_load_time_start.Get().ToInternalValue());
291
292   static bool logged = false;
293   if (!logged) {
294     // Log the delta only once.
295     UMA_HISTOGRAM_TIMES(
296         "VirtualKeyboard.FirstLoadTime",
297         base::Time::Now() - g_keyboard_load_time_start.Get());
298     logged = true;
299   }
300 }
301
302 const GritResourceMap* GetKeyboardExtensionResources(size_t* size) {
303   // This looks a lot like the contents of a resource map; however it is
304   // necessary to have a custom path for the extension path, so the resource
305   // map cannot be used directly.
306   static const GritResourceMap kKeyboardResources[] = {
307       {"keyboard/layouts/function-key-row.html", IDR_KEYBOARD_FUNCTION_KEY_ROW},
308       {"keyboard/images/back.svg", IDR_KEYBOARD_IMAGES_BACK},
309       {"keyboard/images/backspace.png", IDR_KEYBOARD_IMAGES_BACKSPACE},
310       {"keyboard/images/brightness-down.svg",
311        IDR_KEYBOARD_IMAGES_BRIGHTNESS_DOWN},
312       {"keyboard/images/brightness-up.svg", IDR_KEYBOARD_IMAGES_BRIGHTNESS_UP},
313       {"keyboard/images/change-window.svg", IDR_KEYBOARD_IMAGES_CHANGE_WINDOW},
314       {"keyboard/images/down.svg", IDR_KEYBOARD_IMAGES_DOWN},
315       {"keyboard/images/forward.svg", IDR_KEYBOARD_IMAGES_FORWARD},
316       {"keyboard/images/fullscreen.svg", IDR_KEYBOARD_IMAGES_FULLSCREEN},
317       {"keyboard/images/hide-keyboard.png", IDR_KEYBOARD_IMAGES_HIDE_KEYBOARD},
318       {"keyboard/images/keyboard.svg", IDR_KEYBOARD_IMAGES_KEYBOARD},
319       {"keyboard/images/left.svg", IDR_KEYBOARD_IMAGES_LEFT},
320       {"keyboard/images/microphone.svg", IDR_KEYBOARD_IMAGES_MICROPHONE},
321       {"keyboard/images/microphone-green.svg",
322        IDR_KEYBOARD_IMAGES_MICROPHONE_GREEN},
323       {"keyboard/images/mute.svg", IDR_KEYBOARD_IMAGES_MUTE},
324       {"keyboard/images/reload.svg", IDR_KEYBOARD_IMAGES_RELOAD},
325       {"keyboard/images/return.png", IDR_KEYBOARD_IMAGES_RETURN},
326       {"keyboard/images/right.svg", IDR_KEYBOARD_IMAGES_RIGHT},
327       {"keyboard/images/search.png", IDR_KEYBOARD_IMAGES_SEARCH},
328       {"keyboard/images/shift.png", IDR_KEYBOARD_IMAGES_SHIFT},
329       {"keyboard/images/shutdown.svg", IDR_KEYBOARD_IMAGES_SHUTDOWN},
330       {"keyboard/images/tab.png", IDR_KEYBOARD_IMAGES_TAB},
331       {"keyboard/images/up.svg", IDR_KEYBOARD_IMAGES_UP},
332       {"keyboard/images/volume-down.svg", IDR_KEYBOARD_IMAGES_VOLUME_DOWN},
333       {"keyboard/images/volume-up.svg", IDR_KEYBOARD_IMAGES_VOLUME_UP},
334       {"keyboard/index.html", IDR_KEYBOARD_INDEX},
335       {"keyboard/keyboard.js", IDR_KEYBOARD_JS},
336       {"keyboard/keyboard_mojo.js", IDR_KEYBOARD_MOJO_JS},
337       {"keyboard/layouts/numeric.html", IDR_KEYBOARD_LAYOUTS_NUMERIC},
338       {"keyboard/layouts/qwerty.html", IDR_KEYBOARD_LAYOUTS_QWERTY},
339       {"keyboard/layouts/system-qwerty.html",
340        IDR_KEYBOARD_LAYOUTS_SYSTEM_QWERTY},
341       {"keyboard/layouts/spacebar-row.html", IDR_KEYBOARD_SPACEBAR_ROW},
342       {"keyboard/manifest.json", IDR_KEYBOARD_MANIFEST},
343       {"keyboard/main.css", IDR_KEYBOARD_MAIN_CSS},
344       {"keyboard/polymer_loader.js", IDR_KEYBOARD_POLYMER_LOADER},
345       {"keyboard/roboto_bold.ttf", IDR_KEYBOARD_ROBOTO_BOLD_TTF},
346       {"keyboard/sounds/keypress-delete.wav",
347        IDR_KEYBOARD_SOUNDS_KEYPRESS_DELETE},
348       {"keyboard/sounds/keypress-return.wav",
349        IDR_KEYBOARD_SOUNDS_KEYPRESS_RETURN},
350       {"keyboard/sounds/keypress-spacebar.wav",
351        IDR_KEYBOARD_SOUNDS_KEYPRESS_SPACEBAR},
352       {"keyboard/sounds/keypress-standard.wav",
353        IDR_KEYBOARD_SOUNDS_KEYPRESS_STANDARD},
354   };
355   static const size_t kKeyboardResourcesSize = arraysize(kKeyboardResources);
356   *size = kKeyboardResourcesSize;
357   return kKeyboardResources;
358 }
359
360 void SetOverrideContentUrl(const GURL& url) {
361   g_override_content_url.Get() = url;
362 }
363
364 const GURL& GetOverrideContentUrl() {
365   return g_override_content_url.Get();
366 }
367
368 void LogKeyboardControlEvent(KeyboardControlEvent event) {
369   UMA_HISTOGRAM_ENUMERATION(
370       "VirtualKeyboard.KeyboardControlEvent",
371       event,
372       keyboard::KEYBOARD_CONTROL_MAX);
373 }
374
375 }  // namespace keyboard