Add long running gmail memory benchmark for background tab.
[chromium-blink-merge.git] / ui / keyboard / keyboard_util.cc
blobf1753beb42f47778d3107b5479c18848442f6004
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.
5 #include "ui/keyboard/keyboard_util.h"
7 #include <string>
9 #include "base/basictypes.h"
10 #include "base/command_line.h"
11 #include "base/lazy_instance.h"
12 #include "base/logging.h"
13 #include "base/metrics/histogram.h"
14 #include "base/strings/string16.h"
15 #include "grit/keyboard_resources.h"
16 #include "grit/keyboard_resources_map.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/events/event_utils.h"
22 #include "ui/events/keycodes/dom/dom_code.h"
23 #include "ui/events/keycodes/dom/dom_key.h"
24 #include "ui/events/keycodes/dom/keycode_converter.h"
25 #include "ui/events/keycodes/keyboard_code_conversion.h"
26 #include "ui/keyboard/keyboard_controller.h"
27 #include "ui/keyboard/keyboard_controller_proxy.h"
28 #include "ui/keyboard/keyboard_switches.h"
29 #include "url/gurl.h"
31 namespace {
33 const char kKeyDown[] ="keydown";
34 const char kKeyUp[] = "keyup";
36 void SendProcessKeyEvent(ui::EventType type,
37 aura::WindowTreeHost* host) {
38 ui::KeyEvent event(type, ui::VKEY_PROCESSKEY, ui::DomCode::NONE,
39 ui::EF_IS_SYNTHESIZED, ui::DomKey::PROCESS, 0,
40 ui::EventTimeForNow());
41 ui::EventDispatchDetails details =
42 host->event_processor()->OnEventFromSource(&event);
43 CHECK(!details.dispatcher_destroyed);
46 base::LazyInstance<base::Time> g_keyboard_load_time_start =
47 LAZY_INSTANCE_INITIALIZER;
49 bool g_accessibility_keyboard_enabled = false;
51 base::LazyInstance<GURL> g_override_content_url = LAZY_INSTANCE_INITIALIZER;
53 bool g_touch_keyboard_enabled = false;
55 keyboard::KeyboardOverscrolOverride g_keyboard_overscroll_override =
56 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_NONE;
58 keyboard::KeyboardShowOverride g_keyboard_show_override =
59 keyboard::KEYBOARD_SHOW_OVERRIDE_NONE;
61 } // namespace
63 namespace keyboard {
65 gfx::Rect FullWidthKeyboardBoundsFromRootBounds(const gfx::Rect& root_bounds,
66 int keyboard_height) {
67 return gfx::Rect(
68 root_bounds.x(),
69 root_bounds.bottom() - keyboard_height,
70 root_bounds.width(),
71 keyboard_height);
74 void SetAccessibilityKeyboardEnabled(bool enabled) {
75 g_accessibility_keyboard_enabled = enabled;
78 bool GetAccessibilityKeyboardEnabled() {
79 return g_accessibility_keyboard_enabled;
82 void SetTouchKeyboardEnabled(bool enabled) {
83 g_touch_keyboard_enabled = enabled;
86 bool GetTouchKeyboardEnabled() {
87 return g_touch_keyboard_enabled;
90 std::string GetKeyboardLayout() {
91 // TODO(bshe): layout string is currently hard coded. We should use more
92 // standard keyboard layouts.
93 return GetAccessibilityKeyboardEnabled() ? "system-qwerty" : "qwerty";
96 bool IsKeyboardEnabled() {
97 // Accessibility setting prioritized over policy setting.
98 if (g_accessibility_keyboard_enabled)
99 return true;
100 // Policy strictly disables showing a virtual keyboard.
101 if (g_keyboard_show_override == keyboard::KEYBOARD_SHOW_OVERRIDE_DISABLED)
102 return false;
103 // Check if any of the flags are enabled.
104 return base::CommandLine::ForCurrentProcess()->HasSwitch(
105 switches::kEnableVirtualKeyboard) ||
106 g_touch_keyboard_enabled ||
107 (g_keyboard_show_override == keyboard::KEYBOARD_SHOW_OVERRIDE_ENABLED);
110 bool IsKeyboardOverscrollEnabled() {
111 if (!IsKeyboardEnabled())
112 return false;
114 // Users of the accessibility on-screen keyboard are likely to be using mouse
115 // input, which may interfere with overscrolling.
116 if (g_accessibility_keyboard_enabled)
117 return false;
119 // If overscroll enabled override is set, use it instead. Currently
120 // login / out-of-box disable keyboard overscroll. http://crbug.com/363635
121 if (g_keyboard_overscroll_override != KEYBOARD_OVERSCROLL_OVERRIDE_NONE) {
122 return g_keyboard_overscroll_override ==
123 KEYBOARD_OVERSCROLL_OVERRIDE_ENABLED;
126 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
127 switches::kDisableVirtualKeyboardOverscroll)) {
128 return false;
130 return true;
133 void SetKeyboardOverscrollOverride(KeyboardOverscrolOverride override) {
134 g_keyboard_overscroll_override = override;
137 void SetKeyboardShowOverride(KeyboardShowOverride override) {
138 g_keyboard_show_override = override;
141 bool IsInputViewEnabled() {
142 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
143 switches::kEnableInputView))
144 return true;
145 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
146 switches::kDisableInputView))
147 return false;
148 // Default value if no command line flags specified.
149 return true;
152 bool IsExperimentalInputViewEnabled() {
153 return base::CommandLine::ForCurrentProcess()->HasSwitch(
154 switches::kEnableExperimentalInputViewFeatures);
157 bool IsFloatingVirtualKeyboardEnabled() {
158 std::string floating_virtual_keyboard_switch =
159 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
160 switches::kFloatingVirtualKeyboard);
161 return floating_virtual_keyboard_switch ==
162 switches::kFloatingVirtualKeyboardEnabled;
165 bool IsGestureTypingEnabled() {
166 std::string keyboard_switch =
167 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
168 switches::kGestureTyping);
169 return keyboard_switch == switches::kGestureTypingEnabled;
172 bool IsGestureEditingEnabled() {
173 std::string keyboard_switch =
174 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
175 switches::kGestureEditing);
176 return keyboard_switch == switches::kGestureEditingEnabled;
179 bool IsSmartDeployEnabled() {
180 std::string keyboard_switch =
181 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
182 switches::kSmartVirtualKeyboard);
183 return keyboard_switch != switches::kSmartVirtualKeyboardDisabled;
186 bool IsVoiceInputEnabled() {
187 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
188 switches::kDisableVoiceInput);
191 bool InsertText(const base::string16& text) {
192 keyboard::KeyboardController* controller = KeyboardController::GetInstance();
193 if (!controller)
194 return false;
196 ui::InputMethod* input_method = controller->proxy()->GetInputMethod();
197 if (!input_method)
198 return false;
200 ui::TextInputClient* tic = input_method->GetTextInputClient();
201 if (!tic || tic->GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
202 return false;
204 tic->InsertText(text);
206 return true;
209 // TODO(varunjain): It would be cleaner to have something in the
210 // ui::TextInputClient interface, say MoveCaretInDirection(). The code in
211 // here would get the ui::InputMethod from the root_window, and the
212 // ui::TextInputClient from that (see above in InsertText()).
213 bool MoveCursor(int swipe_direction,
214 int modifier_flags,
215 aura::WindowTreeHost* host) {
216 if (!host)
217 return false;
218 ui::DomCode domcodex = ui::DomCode::NONE;
219 ui::DomCode domcodey = ui::DomCode::NONE;
220 if (swipe_direction & kCursorMoveRight)
221 domcodex = ui::DomCode::ARROW_RIGHT;
222 else if (swipe_direction & kCursorMoveLeft)
223 domcodex = ui::DomCode::ARROW_LEFT;
225 if (swipe_direction & kCursorMoveUp)
226 domcodey = ui::DomCode::ARROW_UP;
227 else if (swipe_direction & kCursorMoveDown)
228 domcodey = ui::DomCode::ARROW_DOWN;
230 // First deal with the x movement.
231 if (domcodex != ui::DomCode::NONE) {
232 ui::KeyboardCode codex = ui::VKEY_UNKNOWN;
233 ui::DomKey domkeyx = ui::DomKey::NONE;
234 base::char16 cx;
235 ignore_result(DomCodeToUsLayoutMeaning(domcodex, ui::EF_NONE, &domkeyx,
236 &cx, &codex));
237 ui::KeyEvent press_event(ui::ET_KEY_PRESSED, codex, domcodex,
238 modifier_flags, domkeyx, cx,
239 ui::EventTimeForNow());
240 ui::EventDispatchDetails details =
241 host->event_processor()->OnEventFromSource(&press_event);
242 CHECK(!details.dispatcher_destroyed);
243 ui::KeyEvent release_event(ui::ET_KEY_RELEASED, codex, domcodex,
244 modifier_flags, domkeyx, cx,
245 ui::EventTimeForNow());
246 details = host->event_processor()->OnEventFromSource(&release_event);
247 CHECK(!details.dispatcher_destroyed);
250 // Then deal with the y movement.
251 if (domcodey != ui::DomCode::NONE) {
252 ui::KeyboardCode codey = ui::VKEY_UNKNOWN;
253 ui::DomKey domkeyy = ui::DomKey::NONE;
254 base::char16 cy;
255 ignore_result(DomCodeToUsLayoutMeaning(domcodey, ui::EF_NONE, &domkeyy,
256 &cy, &codey));
257 ui::KeyEvent press_event(ui::ET_KEY_PRESSED, codey, domcodey,
258 modifier_flags, domkeyy, cy,
259 ui::EventTimeForNow());
260 ui::EventDispatchDetails details =
261 host->event_processor()->OnEventFromSource(&press_event);
262 CHECK(!details.dispatcher_destroyed);
263 ui::KeyEvent release_event(ui::ET_KEY_RELEASED, codey, domcodey,
264 modifier_flags, domkeyy, cy,
265 ui::EventTimeForNow());
266 details = host->event_processor()->OnEventFromSource(&release_event);
267 CHECK(!details.dispatcher_destroyed);
269 return true;
272 bool SendKeyEvent(const std::string type,
273 int key_value,
274 int key_code,
275 std::string key_name,
276 int modifiers,
277 aura::WindowTreeHost* host) {
278 ui::EventType event_type = ui::ET_UNKNOWN;
279 if (type == kKeyDown)
280 event_type = ui::ET_KEY_PRESSED;
281 else if (type == kKeyUp)
282 event_type = ui::ET_KEY_RELEASED;
283 if (event_type == ui::ET_UNKNOWN)
284 return false;
286 ui::KeyboardCode code = static_cast<ui::KeyboardCode>(key_code);
288 ui::InputMethod* input_method = host->GetInputMethod();
289 if (code == ui::VKEY_UNKNOWN) {
290 // Handling of special printable characters (e.g. accented characters) for
291 // which there is no key code.
292 if (event_type == ui::ET_KEY_RELEASED) {
293 if (!input_method)
294 return false;
296 ui::TextInputClient* tic = input_method->GetTextInputClient();
298 SendProcessKeyEvent(ui::ET_KEY_PRESSED, host);
299 tic->InsertChar(static_cast<uint16>(key_value), ui::EF_NONE);
300 SendProcessKeyEvent(ui::ET_KEY_RELEASED, host);
302 } else {
303 if (event_type == ui::ET_KEY_RELEASED) {
304 // The number of key press events seen since the last backspace.
305 static int keys_seen = 0;
306 if (code == ui::VKEY_BACK) {
307 // Log the rough lengths of characters typed between backspaces. This
308 // metric will be used to determine the error rate for the keyboard.
309 UMA_HISTOGRAM_CUSTOM_COUNTS(
310 "VirtualKeyboard.KeystrokesBetweenBackspaces",
311 keys_seen, 1, 1000, 50);
312 keys_seen = 0;
313 } else {
314 ++keys_seen;
318 ui::DomCode dom_code = ui::DomCode::NONE;
319 if (!key_name.empty())
320 dom_code = ui::KeycodeConverter::CodeStringToDomCode(key_name.c_str());
321 if (dom_code == ui::DomCode::NONE)
322 dom_code = ui::UsLayoutKeyboardCodeToDomCode(code);
323 CHECK(dom_code != ui::DomCode::NONE);
324 ui::KeyEvent event(
325 event_type,
326 code,
327 dom_code,
328 modifiers);
329 if (input_method) {
330 input_method->DispatchKeyEvent(event);
331 } else {
332 ui::EventDispatchDetails details =
333 host->event_processor()->OnEventFromSource(&event);
334 CHECK(!details.dispatcher_destroyed);
337 return true;
340 void MarkKeyboardLoadStarted() {
341 if (!g_keyboard_load_time_start.Get().ToInternalValue())
342 g_keyboard_load_time_start.Get() = base::Time::Now();
345 void MarkKeyboardLoadFinished() {
346 // Possible to get a load finished without a start if navigating directly to
347 // chrome://keyboard.
348 if (!g_keyboard_load_time_start.Get().ToInternalValue())
349 return;
351 // It should not be possible to finish loading the keyboard without starting
352 // to load it first.
353 DCHECK(g_keyboard_load_time_start.Get().ToInternalValue());
355 static bool logged = false;
356 if (!logged) {
357 // Log the delta only once.
358 UMA_HISTOGRAM_TIMES(
359 "VirtualKeyboard.FirstLoadTime",
360 base::Time::Now() - g_keyboard_load_time_start.Get());
361 logged = true;
365 const GritResourceMap* GetKeyboardExtensionResources(size_t* size) {
366 // This looks a lot like the contents of a resource map; however it is
367 // necessary to have a custom path for the extension path, so the resource
368 // map cannot be used directly.
369 static const GritResourceMap kKeyboardResources[] = {
370 {"keyboard/locales/en.js", IDR_KEYBOARD_LOCALES_EN},
371 {"keyboard/config/emoji.js", IDR_KEYBOARD_CONFIG_EMOJI},
372 {"keyboard/config/hwt.js", IDR_KEYBOARD_CONFIG_HWT},
373 {"keyboard/config/us.js", IDR_KEYBOARD_CONFIG_US},
374 {"keyboard/emoji.css", IDR_KEYBOARD_CSS_EMOJI},
375 {"keyboard/images/3dots.png", IDR_KEYBOARD_IMAGES_3_DOTS},
376 {"keyboard/images/back_to_keyboard.png",
377 IDR_KEYBOARD_IMAGES_BACK_TO_KEYBOARD},
378 {"keyboard/images/backspace.png", IDR_KEYBOARD_IMAGES_BACKSPACE},
379 {"keyboard/images/car.png", IDR_KEYBOARD_IMAGES_CAR},
380 {"keyboard/images/check.png", IDR_KEYBOARD_IMAGES_CHECK},
381 {"keyboard/images/check_in_menu.png", IDR_KEYBOARD_IMAGES_CHECK_IN_MENU},
382 {"keyboard/images/compact.png", IDR_KEYBOARD_IMAGES_COMPACT},
383 {"keyboard/images/down.png", IDR_KEYBOARD_IMAGES_DOWN},
384 {"keyboard/images/emoji.png", IDR_KEYBOARD_IMAGES_EMOJI},
385 {"keyboard/images/emoji_car.png", IDR_KEYBOARD_IMAGES_EMOJI_CAR},
386 {"keyboard/images/emoji_crown.png", IDR_KEYBOARD_IMAGES_EMOJI_CROWN},
387 {"keyboard/images/emoji_emoticon.png",
388 IDR_KEYBOARD_IMAGES_EMOJI_EMOTICON},
389 {"keyboard/images/emoji_flower.png", IDR_KEYBOARD_IMAGES_EMOJI_FLOWER},
390 {"keyboard/images/emoji_hot.png", IDR_KEYBOARD_IMAGES_EMOJI_HOT},
391 {"keyboard/images/emoji_recent.png", IDR_KEYBOARD_IMAGES_EMOJI_RECENT},
392 {"keyboard/images/emoji_shape.png", IDR_KEYBOARD_IMAGES_EMOJI_SHAPE},
393 {"keyboard/images/emoji_cat_items.png", IDR_KEYBOARD_IMAGES_CAT},
394 {"keyboard/images/emoticon.png", IDR_KEYBOARD_IMAGES_EMOTICON},
395 {"keyboard/images/enter.png", IDR_KEYBOARD_IMAGES_RETURN},
396 {"keyboard/images/error.png", IDR_KEYBOARD_IMAGES_ERROR},
397 {"keyboard/images/favorit.png", IDR_KEYBOARD_IMAGES_FAVORITE},
398 {"keyboard/images/flower.png", IDR_KEYBOARD_IMAGES_FLOWER},
399 {"keyboard/images/globe.png", IDR_KEYBOARD_IMAGES_GLOBE},
400 {"keyboard/images/hide.png", IDR_KEYBOARD_IMAGES_HIDE},
401 {"keyboard/images/hidekeyboard.png", IDR_KEYBOARD_IMAGES_HIDE_KEYBOARD},
402 {"keyboard/images/keyboard.svg", IDR_KEYBOARD_IMAGES_KEYBOARD},
403 {"keyboard/images/left.png", IDR_KEYBOARD_IMAGES_LEFT},
404 {"keyboard/images/penci.png", IDR_KEYBOARD_IMAGES_PENCIL},
405 {"keyboard/images/recent.png", IDR_KEYBOARD_IMAGES_RECENT},
406 {"keyboard/images/regular_size.png", IDR_KEYBOARD_IMAGES_FULLSIZE},
407 {"keyboard/images/menu.png", IDR_KEYBOARD_IMAGES_MENU},
408 {"keyboard/images/pencil.png", IDR_KEYBOARD_IMAGES_PENCIL},
409 {"keyboard/images/right.png", IDR_KEYBOARD_IMAGES_RIGHT},
410 {"keyboard/images/search.png", IDR_KEYBOARD_IMAGES_SEARCH},
411 {"keyboard/images/select_right.png", IDR_KEYBOARD_IMAGES_SELECT_RIGHT},
412 {"keyboard/images/select_left.png", IDR_KEYBOARD_IMAGES_SELECT_LEFT},
413 {"keyboard/images/setting.png", IDR_KEYBOARD_IMAGES_SETTINGS},
414 {"keyboard/images/shift.png", IDR_KEYBOARD_IMAGES_SHIFT},
415 {"keyboard/images/space.png", IDR_KEYBOARD_IMAGES_SPACE},
416 {"keyboard/images/tab.png", IDR_KEYBOARD_IMAGES_TAB},
417 {"keyboard/images/tab_in_fullsize.png",
418 IDR_KEYBOARD_IMAGES_TAB_IN_FULLSIZE},
419 {"keyboard/images/triangle.png", IDR_KEYBOARD_IMAGES_TRIANGLE},
420 {"keyboard/images/up.png", IDR_KEYBOARD_IMAGES_UP},
421 {"keyboard/index.html", IDR_KEYBOARD_INDEX},
422 {"keyboard/inputview_adapter.js", IDR_KEYBOARD_INPUTVIEW_ADAPTER},
423 {"keyboard/inputview.css", IDR_KEYBOARD_INPUTVIEW_CSS},
424 {"keyboard/inputview.js", IDR_KEYBOARD_INPUTVIEW_JS},
425 {"keyboard/inputview_layouts/101kbd.js", IDR_KEYBOARD_LAYOUTS_101},
426 {"keyboard/inputview_layouts/compactkbd-qwerty.js",
427 IDR_KEYBOARD_LAYOUTS_COMPACT_QWERTY},
428 {"keyboard/inputview_layouts/compactkbd-numberpad.js",
429 IDR_KEYBOARD_LAYOUTS_COMPACT_NUMBERPAD},
430 {"keyboard/inputview_layouts/emoji.js", IDR_KEYBOARD_LAYOUTS_EMOJI},
431 {"keyboard/inputview_layouts/handwriting.js", IDR_KEYBOARD_LAYOUTS_HWT},
432 {"keyboard/manifest.json", IDR_KEYBOARD_MANIFEST},
433 {"keyboard/sounds/keypress-delete.wav",
434 IDR_KEYBOARD_SOUNDS_KEYPRESS_DELETE},
435 {"keyboard/sounds/keypress-return.wav",
436 IDR_KEYBOARD_SOUNDS_KEYPRESS_RETURN},
437 {"keyboard/sounds/keypress-spacebar.wav",
438 IDR_KEYBOARD_SOUNDS_KEYPRESS_SPACEBAR},
439 {"keyboard/sounds/keypress-standard.wav",
440 IDR_KEYBOARD_SOUNDS_KEYPRESS_STANDARD},
442 static const size_t kKeyboardResourcesSize = arraysize(kKeyboardResources);
443 *size = kKeyboardResourcesSize;
444 return kKeyboardResources;
447 void SetOverrideContentUrl(const GURL& url) {
448 g_override_content_url.Get() = url;
451 const GURL& GetOverrideContentUrl() {
452 return g_override_content_url.Get();
455 void LogKeyboardControlEvent(KeyboardControlEvent event) {
456 UMA_HISTOGRAM_ENUMERATION(
457 "VirtualKeyboard.KeyboardControlEvent",
458 event,
459 keyboard::KEYBOARD_CONTROL_MAX);
462 } // namespace keyboard