blob: 64c71a804719d6398814b0f812f5f85bbf669052 [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/keyboard/keyboard_util.h"
#include <string>
#include "base/command_line.h"
#include "base/metrics/histogram_macros.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/ime/constants.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/events/event_sink.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/dom_key.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
#include "ui/keyboard/keyboard_controller.h"
#include "ui/keyboard/keyboard_switches.h"
namespace keyboard {
namespace {
const char kKeyDown[] = "keydown";
const char kKeyUp[] = "keyup";
void SendProcessKeyEvent(ui::EventType type, aura::WindowTreeHost* host) {
ui::KeyEvent event(type, ui::VKEY_PROCESSKEY, ui::DomCode::NONE,
ui::EF_IS_SYNTHESIZED, ui::DomKey::PROCESS,
ui::EventTimeForNow());
ui::EventDispatchDetails details =
host->event_sink()->OnEventFromSource(&event);
CHECK(!details.dispatcher_destroyed);
}
// Until src/chrome is fully transitioned to use ChromeKeyboardControllerClient
// we need to test whether KeyboardController exists; it is null in OopMash.
// TODO(stevenjb): Remove remaining calls from src/chrome.
// https://crbug.com/84332.
bool GetFlag(mojom::KeyboardEnableFlag flag) {
auto* controller = KeyboardController::Get();
return controller ? controller->IsEnableFlagSet(flag) : false;
}
void SetOrClearEnableFlag(mojom::KeyboardEnableFlag flag, bool enabled) {
auto* controller = KeyboardController::Get();
if (!controller)
return;
if (enabled)
controller->SetEnableFlag(flag);
else
controller->ClearEnableFlag(flag);
}
} // namespace
void SetAccessibilityKeyboardEnabled(bool enabled) {
SetOrClearEnableFlag(mojom::KeyboardEnableFlag::kAccessibilityEnabled,
enabled);
}
bool GetAccessibilityKeyboardEnabled() {
return GetFlag(mojom::KeyboardEnableFlag::kAccessibilityEnabled);
}
void SetKeyboardEnabledFromShelf(bool enabled) {
SetOrClearEnableFlag(mojom::KeyboardEnableFlag::kShelfEnabled, enabled);
}
bool GetKeyboardEnabledFromShelf() {
return GetFlag(mojom::KeyboardEnableFlag::kShelfEnabled);
}
void SetTouchKeyboardEnabled(bool enabled) {
SetOrClearEnableFlag(mojom::KeyboardEnableFlag::kTouchEnabled, enabled);
}
bool GetTouchKeyboardEnabled() {
return GetFlag(mojom::KeyboardEnableFlag::kTouchEnabled);
}
std::string GetKeyboardLayout() {
// TODO(bshe): layout string is currently hard coded. We should use more
// standard keyboard layouts.
return GetAccessibilityKeyboardEnabled() ? "system-qwerty" : "qwerty";
}
bool IsKeyboardEnabled() {
return KeyboardController::Get()->IsKeyboardEnableRequested();
}
bool SendKeyEvent(const std::string type,
int key_value,
int key_code,
std::string key_name,
int modifiers,
aura::WindowTreeHost* host) {
ui::EventType event_type = ui::ET_UNKNOWN;
if (type == kKeyDown)
event_type = ui::ET_KEY_PRESSED;
else if (type == kKeyUp)
event_type = ui::ET_KEY_RELEASED;
if (event_type == ui::ET_UNKNOWN)
return false;
ui::KeyboardCode code = static_cast<ui::KeyboardCode>(key_code);
ui::InputMethod* input_method = host->GetInputMethod();
if (code == ui::VKEY_UNKNOWN) {
// Handling of special printable characters (e.g. accented characters) for
// which there is no key code.
if (event_type == ui::ET_KEY_RELEASED) {
if (!input_method)
return false;
// This can be null if no text input field is not focused.
ui::TextInputClient* tic = input_method->GetTextInputClient();
SendProcessKeyEvent(ui::ET_KEY_PRESSED, host);
ui::KeyEvent char_event(key_value, code, ui::DomCode::NONE, ui::EF_NONE);
if (tic)
tic->InsertChar(char_event);
SendProcessKeyEvent(ui::ET_KEY_RELEASED, host);
}
} else {
if (event_type == ui::ET_KEY_RELEASED) {
// The number of key press events seen since the last backspace.
static int keys_seen = 0;
if (code == ui::VKEY_BACK) {
// Log the rough lengths of characters typed between backspaces. This
// metric will be used to determine the error rate for the keyboard.
UMA_HISTOGRAM_CUSTOM_COUNTS(
"VirtualKeyboard.KeystrokesBetweenBackspaces", keys_seen, 1, 1000,
50);
keys_seen = 0;
} else {
++keys_seen;
}
}
ui::DomCode dom_code = ui::KeycodeConverter::CodeStringToDomCode(key_name);
if (dom_code == ui::DomCode::NONE)
dom_code = ui::UsLayoutKeyboardCodeToDomCode(code);
CHECK(dom_code != ui::DomCode::NONE);
ui::KeyEvent event(event_type, code, dom_code, modifiers);
// Marks the simulated key event is from the Virtual Keyboard.
ui::Event::Properties properties;
properties[ui::kPropertyFromVK] = std::vector<uint8_t>();
event.SetProperties(properties);
ui::EventDispatchDetails details =
host->event_sink()->OnEventFromSource(&event);
CHECK(!details.dispatcher_destroyed);
}
return true;
}
} // namespace keyboard