Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / ui / keyboard / keyboard_util.cc
blob7b77b438ff792b9c462c541d1a06900393feaf02
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/client/aura_constants.h"
18 #include "ui/aura/window_tree_host.h"
19 #include "ui/base/ime/input_method.h"
20 #include "ui/base/ime/text_input_client.h"
21 #include "ui/events/event_processor.h"
22 #include "ui/events/event_utils.h"
23 #include "ui/events/keycodes/dom3/dom_code.h"
24 #include "ui/events/keycodes/dom3/dom_key.h"
25 #include "ui/events/keycodes/dom4/keycode_converter.h"
26 #include "ui/events/keycodes/keyboard_code_conversion.h"
27 #include "ui/keyboard/keyboard_controller.h"
28 #include "ui/keyboard/keyboard_controller_proxy.h"
29 #include "ui/keyboard/keyboard_switches.h"
30 #include "url/gurl.h"
32 namespace {
34 const char kKeyDown[] ="keydown";
35 const char kKeyUp[] = "keyup";
37 void SendProcessKeyEvent(ui::EventType type,
38 aura::WindowTreeHost* host) {
39 ui::KeyEvent event(type, ui::VKEY_PROCESSKEY, ui::DomCode::NONE, ui::EF_NONE,
40 ui::DomKey::PROCESS, 0, ui::EventTimeForNow());
41 event.SetTranslated(true);
42 ui::EventDispatchDetails details =
43 host->event_processor()->OnEventFromSource(&event);
44 CHECK(!details.dispatcher_destroyed);
47 base::LazyInstance<base::Time> g_keyboard_load_time_start =
48 LAZY_INSTANCE_INITIALIZER;
50 bool g_accessibility_keyboard_enabled = false;
52 base::LazyInstance<GURL> g_override_content_url = LAZY_INSTANCE_INITIALIZER;
54 bool g_touch_keyboard_enabled = false;
56 keyboard::KeyboardOverscrolOverride g_keyboard_overscroll_override =
57 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_NONE;
59 keyboard::KeyboardShowOverride g_keyboard_show_override =
60 keyboard::KEYBOARD_SHOW_OVERRIDE_NONE;
62 } // namespace
64 namespace keyboard {
66 gfx::Rect FullWidthKeyboardBoundsFromRootBounds(const gfx::Rect& root_bounds,
67 int keyboard_height) {
68 return gfx::Rect(
69 root_bounds.x(),
70 root_bounds.bottom() - keyboard_height,
71 root_bounds.width(),
72 keyboard_height);
75 void SetAccessibilityKeyboardEnabled(bool enabled) {
76 g_accessibility_keyboard_enabled = enabled;
79 bool GetAccessibilityKeyboardEnabled() {
80 return g_accessibility_keyboard_enabled;
83 void SetTouchKeyboardEnabled(bool enabled) {
84 g_touch_keyboard_enabled = enabled;
87 bool GetTouchKeyboardEnabled() {
88 return g_touch_keyboard_enabled;
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";
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 base::CommandLine::ForCurrentProcess()->HasSwitch(
106 switches::kEnableVirtualKeyboard) ||
107 g_touch_keyboard_enabled ||
108 (g_keyboard_show_override == keyboard::KEYBOARD_SHOW_OVERRIDE_ENABLED);
111 bool IsKeyboardOverscrollEnabled() {
112 if (!IsKeyboardEnabled())
113 return false;
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;
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;
127 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
128 switches::kDisableVirtualKeyboardOverscroll)) {
129 return false;
131 return true;
134 void SetKeyboardOverscrollOverride(KeyboardOverscrolOverride override) {
135 g_keyboard_overscroll_override = override;
138 void SetKeyboardShowOverride(KeyboardShowOverride override) {
139 g_keyboard_show_override = override;
142 bool IsInputViewEnabled() {
143 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
144 switches::kEnableInputView))
145 return true;
146 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
147 switches::kDisableInputView))
148 return false;
149 // Default value if no command line flags specified.
150 return true;
153 bool IsExperimentalInputViewEnabled() {
154 return base::CommandLine::ForCurrentProcess()->HasSwitch(
155 switches::kEnableExperimentalInputViewFeatures);
158 bool IsGestureTypingEnabled() {
159 return base::CommandLine::ForCurrentProcess()->HasSwitch(
160 switches::kEnableGestureTyping);
163 bool IsGestureSelectionEnabled() {
164 return base::CommandLine::ForCurrentProcess()->HasSwitch(
165 switches::kEnableGestureSelection);
168 bool IsGestureDeletionEnabled() {
169 return base::CommandLine::ForCurrentProcess()->HasSwitch(
170 switches::kEnableGestureDeletion);
173 bool InsertText(const base::string16& text) {
174 keyboard::KeyboardController* controller = KeyboardController::GetInstance();
175 if (!controller)
176 return false;
178 ui::InputMethod* input_method = controller->proxy()->GetInputMethod();
179 if (!input_method)
180 return false;
182 ui::TextInputClient* tic = input_method->GetTextInputClient();
183 if (!tic || tic->GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
184 return false;
186 tic->InsertText(text);
188 return true;
191 // TODO(varunjain): It would be cleaner to have something in the
192 // ui::TextInputClient interface, say MoveCaretInDirection(). The code in
193 // here would get the ui::InputMethod from the root_window, and the
194 // ui::TextInputClient from that (see above in InsertText()).
195 bool MoveCursor(int swipe_direction,
196 int modifier_flags,
197 aura::WindowTreeHost* host) {
198 if (!host)
199 return false;
200 ui::DomCode domcodex = ui::DomCode::NONE;
201 ui::DomCode domcodey = ui::DomCode::NONE;
202 if (swipe_direction & kCursorMoveRight)
203 domcodex = ui::DomCode::ARROW_RIGHT;
204 else if (swipe_direction & kCursorMoveLeft)
205 domcodex = ui::DomCode::ARROW_LEFT;
207 if (swipe_direction & kCursorMoveUp)
208 domcodey = ui::DomCode::ARROW_UP;
209 else if (swipe_direction & kCursorMoveDown)
210 domcodey = ui::DomCode::ARROW_DOWN;
212 // First deal with the x movement.
213 if (domcodex != ui::DomCode::NONE) {
214 ui::KeyboardCode codex = ui::VKEY_UNKNOWN;
215 ui::DomKey domkeyx = ui::DomKey::NONE;
216 base::char16 cx;
217 ignore_result(DomCodeToUsLayoutMeaning(domcodex, ui::EF_NONE, &domkeyx,
218 &cx, &codex));
219 ui::KeyEvent press_event(ui::ET_KEY_PRESSED, codex, domcodex,
220 modifier_flags, domkeyx, cx,
221 ui::EventTimeForNow());
222 ui::EventDispatchDetails details =
223 host->event_processor()->OnEventFromSource(&press_event);
224 CHECK(!details.dispatcher_destroyed);
225 ui::KeyEvent release_event(ui::ET_KEY_RELEASED, codex, domcodex,
226 modifier_flags, domkeyx, cx,
227 ui::EventTimeForNow());
228 details = host->event_processor()->OnEventFromSource(&release_event);
229 CHECK(!details.dispatcher_destroyed);
232 // Then deal with the y movement.
233 if (domcodey != ui::DomCode::NONE) {
234 ui::KeyboardCode codey = ui::VKEY_UNKNOWN;
235 ui::DomKey domkeyy = ui::DomKey::NONE;
236 base::char16 cy;
237 ignore_result(DomCodeToUsLayoutMeaning(domcodey, ui::EF_NONE, &domkeyy,
238 &cy, &codey));
239 ui::KeyEvent press_event(ui::ET_KEY_PRESSED, codey, domcodey,
240 modifier_flags, domkeyy, cy,
241 ui::EventTimeForNow());
242 ui::EventDispatchDetails details =
243 host->event_processor()->OnEventFromSource(&press_event);
244 CHECK(!details.dispatcher_destroyed);
245 ui::KeyEvent release_event(ui::ET_KEY_RELEASED, codey, domcodey,
246 modifier_flags, domkeyy, cy,
247 ui::EventTimeForNow());
248 details = host->event_processor()->OnEventFromSource(&release_event);
249 CHECK(!details.dispatcher_destroyed);
251 return true;
254 bool SendKeyEvent(const std::string type,
255 int key_value,
256 int key_code,
257 std::string key_name,
258 int modifiers,
259 aura::WindowTreeHost* host) {
260 ui::EventType event_type = ui::ET_UNKNOWN;
261 if (type == kKeyDown)
262 event_type = ui::ET_KEY_PRESSED;
263 else if (type == kKeyUp)
264 event_type = ui::ET_KEY_RELEASED;
265 if (event_type == ui::ET_UNKNOWN)
266 return false;
268 ui::KeyboardCode code = static_cast<ui::KeyboardCode>(key_code);
270 if (code == ui::VKEY_UNKNOWN) {
271 // Handling of special printable characters (e.g. accented characters) for
272 // which there is no key code.
273 if (event_type == ui::ET_KEY_RELEASED) {
274 ui::InputMethod* input_method = host->window()->GetProperty(
275 aura::client::kRootWindowInputMethodKey);
276 if (!input_method)
277 return false;
279 ui::TextInputClient* tic = input_method->GetTextInputClient();
281 SendProcessKeyEvent(ui::ET_KEY_PRESSED, host);
282 tic->InsertChar(static_cast<uint16>(key_value), ui::EF_NONE);
283 SendProcessKeyEvent(ui::ET_KEY_RELEASED, host);
285 } else {
286 if (event_type == ui::ET_KEY_RELEASED) {
287 // The number of key press events seen since the last backspace.
288 static int keys_seen = 0;
289 if (code == ui::VKEY_BACK) {
290 // Log the rough lengths of characters typed between backspaces. This
291 // metric will be used to determine the error rate for the keyboard.
292 UMA_HISTOGRAM_CUSTOM_COUNTS(
293 "VirtualKeyboard.KeystrokesBetweenBackspaces",
294 keys_seen, 1, 1000, 50);
295 keys_seen = 0;
296 } else {
297 ++keys_seen;
301 ui::DomCode dom_code = ui::DomCode::NONE;
302 if (!key_name.empty())
303 dom_code = ui::KeycodeConverter::CodeStringToDomCode(key_name.c_str());
304 if (dom_code == ui::DomCode::NONE)
305 dom_code = ui::UsLayoutKeyboardCodeToDomCode(code);
306 CHECK(dom_code != ui::DomCode::NONE);
307 ui::KeyEvent event(
308 event_type,
309 code,
310 dom_code,
311 modifiers);
312 ui::EventDispatchDetails details =
313 host->event_processor()->OnEventFromSource(&event);
314 CHECK(!details.dispatcher_destroyed);
316 return true;
319 void MarkKeyboardLoadStarted() {
320 if (!g_keyboard_load_time_start.Get().ToInternalValue())
321 g_keyboard_load_time_start.Get() = base::Time::Now();
324 void MarkKeyboardLoadFinished() {
325 // Possible to get a load finished without a start if navigating directly to
326 // chrome://keyboard.
327 if (!g_keyboard_load_time_start.Get().ToInternalValue())
328 return;
330 // It should not be possible to finish loading the keyboard without starting
331 // to load it first.
332 DCHECK(g_keyboard_load_time_start.Get().ToInternalValue());
334 static bool logged = false;
335 if (!logged) {
336 // Log the delta only once.
337 UMA_HISTOGRAM_TIMES(
338 "VirtualKeyboard.FirstLoadTime",
339 base::Time::Now() - g_keyboard_load_time_start.Get());
340 logged = true;
344 const GritResourceMap* GetKeyboardExtensionResources(size_t* size) {
345 // This looks a lot like the contents of a resource map; however it is
346 // necessary to have a custom path for the extension path, so the resource
347 // map cannot be used directly.
348 static const GritResourceMap kKeyboardResources[] = {
349 {"keyboard/locales/en.js", IDR_KEYBOARD_LOCALES_EN},
350 {"keyboard/config/m-emoji.js", IDR_KEYBOARD_CONFIG_EMOJI},
351 {"keyboard/config/m-hwt.js", IDR_KEYBOARD_CONFIG_HWT},
352 {"keyboard/config/us.js", IDR_KEYBOARD_CONFIG_US},
353 {"keyboard/emoji.css", IDR_KEYBOARD_CSS_EMOJI},
354 {"keyboard/images/backspace.png", IDR_KEYBOARD_IMAGES_BACKSPACE},
355 {"keyboard/images/car.png", IDR_KEYBOARD_IMAGES_CAR},
356 {"keyboard/images/check.png", IDR_KEYBOARD_IMAGES_CHECK},
357 {"keyboard/images/compact.png", IDR_KEYBOARD_IMAGES_COMPACT},
358 {"keyboard/images/down.png", IDR_KEYBOARD_IMAGES_DOWN},
359 {"keyboard/images/emoji.png", IDR_KEYBOARD_IMAGES_EMOJI},
360 {"keyboard/images/emoji_cat_items.png", IDR_KEYBOARD_IMAGES_CAT},
361 {"keyboard/images/emoticon.png", IDR_KEYBOARD_IMAGES_EMOTICON},
362 {"keyboard/images/enter.png", IDR_KEYBOARD_IMAGES_RETURN},
363 {"keyboard/images/error.png", IDR_KEYBOARD_IMAGES_ERROR},
364 {"keyboard/images/favorit.png", IDR_KEYBOARD_IMAGES_FAVORITE},
365 {"keyboard/images/flower.png", IDR_KEYBOARD_IMAGES_FLOWER},
366 {"keyboard/images/globe.png", IDR_KEYBOARD_IMAGES_GLOBE},
367 {"keyboard/images/hide.png", IDR_KEYBOARD_IMAGES_HIDE_KEYBOARD},
368 {"keyboard/images/keyboard.svg", IDR_KEYBOARD_IMAGES_KEYBOARD},
369 {"keyboard/images/left.png", IDR_KEYBOARD_IMAGES_LEFT},
370 {"keyboard/images/penci.png", IDR_KEYBOARD_IMAGES_PENCIL},
371 {"keyboard/images/recent.png", IDR_KEYBOARD_IMAGES_RECENT},
372 {"keyboard/images/regular_size.png", IDR_KEYBOARD_IMAGES_FULLSIZE},
373 {"keyboard/images/menu.png", IDR_KEYBOARD_IMAGES_MENU},
374 {"keyboard/images/pencil.png", IDR_KEYBOARD_IMAGES_PENCIL},
375 {"keyboard/images/right.png", IDR_KEYBOARD_IMAGES_RIGHT},
376 {"keyboard/images/search.png", IDR_KEYBOARD_IMAGES_SEARCH},
377 {"keyboard/images/setting.png", IDR_KEYBOARD_IMAGES_SETTINGS},
378 {"keyboard/images/shift.png", IDR_KEYBOARD_IMAGES_SHIFT},
379 {"keyboard/images/space.png", IDR_KEYBOARD_IMAGES_SPACE},
380 {"keyboard/images/tab.png", IDR_KEYBOARD_IMAGES_TAB},
381 {"keyboard/images/triangle.png", IDR_KEYBOARD_IMAGES_TRIANGLE},
382 {"keyboard/images/up.png", IDR_KEYBOARD_IMAGES_UP},
383 {"keyboard/index.html", IDR_KEYBOARD_INDEX},
384 {"keyboard/inputview_adapter.js", IDR_KEYBOARD_INPUTVIEW_ADAPTER},
385 {"keyboard/inputview.css", IDR_KEYBOARD_INPUTVIEW_CSS},
386 {"keyboard/inputview.js", IDR_KEYBOARD_INPUTVIEW_JS},
387 {"keyboard/inputview_layouts/101kbd.js", IDR_KEYBOARD_LAYOUTS_101},
388 {"keyboard/inputview_layouts/compactkbd-qwerty.js",
389 IDR_KEYBOARD_LAYOUTS_COMPACT_QWERTY},
390 {"keyboard/inputview_layouts/compactkbd-numberpad.js",
391 IDR_KEYBOARD_LAYOUTS_COMPACT_NUMBERPAD},
392 {"keyboard/inputview_layouts/emoji.js", IDR_KEYBOARD_LAYOUTS_EMOJI},
393 {"keyboard/inputview_layouts/handwriting.js", IDR_KEYBOARD_LAYOUTS_HWT},
394 {"keyboard/inputview_layouts/m-101kbd.js",
395 IDR_KEYBOARD_LAYOUTS_MATERIAL_101},
396 {"keyboard/inputview_layouts/m-compactkbd-qwerty.js",
397 IDR_KEYBOARD_LAYOUTS_MATERIAL_COMPACT_QWERTY},
398 {"keyboard/inputview_layouts/m-compactkbd-numberpad.js",
399 IDR_KEYBOARD_LAYOUTS_MATERIAL_COMPACT_NUMBERPAD},
400 {"keyboard/inputview_layouts/m-emoji.js",
401 IDR_KEYBOARD_LAYOUTS_MATERIAL_EMOJI},
402 {"keyboard/inputview_layouts/m-handwriting.js",
403 IDR_KEYBOARD_LAYOUTS_MATERIAL_HWT},
404 {"keyboard/manifest.json", IDR_KEYBOARD_MANIFEST},
405 {"keyboard/sounds/keypress-delete.wav",
406 IDR_KEYBOARD_SOUNDS_KEYPRESS_DELETE},
407 {"keyboard/sounds/keypress-return.wav",
408 IDR_KEYBOARD_SOUNDS_KEYPRESS_RETURN},
409 {"keyboard/sounds/keypress-spacebar.wav",
410 IDR_KEYBOARD_SOUNDS_KEYPRESS_SPACEBAR},
411 {"keyboard/sounds/keypress-standard.wav",
412 IDR_KEYBOARD_SOUNDS_KEYPRESS_STANDARD},
414 static const size_t kKeyboardResourcesSize = arraysize(kKeyboardResources);
415 *size = kKeyboardResourcesSize;
416 return kKeyboardResources;
419 void SetOverrideContentUrl(const GURL& url) {
420 g_override_content_url.Get() = url;
423 const GURL& GetOverrideContentUrl() {
424 return g_override_content_url.Get();
427 void LogKeyboardControlEvent(KeyboardControlEvent event) {
428 UMA_HISTOGRAM_ENUMERATION(
429 "VirtualKeyboard.KeyboardControlEvent",
430 event,
431 keyboard::KEYBOARD_CONTROL_MAX);
434 } // namespace keyboard