1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
|
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/keyboard/virtual_keyboard_controller.h"
#include <vector>
#include "ash/constants/ash_features.h"
#include "ash/ime/ime_controller_impl.h"
#include "ash/keyboard/keyboard_controller_impl.h"
#include "ash/keyboard/ui/keyboard_ui_controller.h"
#include "ash/keyboard/ui/keyboard_util.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/system/tray/system_tray_notifier.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/strings/string_util.h"
#include "base/task/single_thread_task_runner.h"
#include "ui/base/emoji/emoji_panel_helper.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/events/devices/device_data_manager.h"
#include "ui/events/devices/input_device.h"
namespace ash {
namespace {
void ResetVirtualKeyboard() {
keyboard::SetKeyboardEnabledFromShelf(false);
// This function can get called asynchronously after the shell has been
// destroyed, so check for an instance.
if (Shell::HasInstance()) {
// Reset the keyset after disabling the virtual keyboard to prevent the IME
// extension from accidentally loading the default keyset while it's
// shutting down. See https://crbug.com/875456.
Shell::Get()->ime_controller()->OverrideKeyboardKeyset(
input_method::ImeKeyset::kNone);
}
}
} // namespace
VirtualKeyboardController::VirtualKeyboardController()
: ignore_external_keyboard_(false),
ignore_internal_keyboard_(false),
bluetooth_devices_observer_(
std::make_unique<BluetoothDevicesObserver>(base::BindRepeating(
&VirtualKeyboardController::OnBluetoothAdapterOrDeviceChanged,
base::Unretained(this)))) {
Shell::Get()->tablet_mode_controller()->AddObserver(this);
Shell::Get()->session_controller()->AddObserver(this);
ui::DeviceDataManager::GetInstance()->AddObserver(this);
UpdateDevices();
// Set callback to show the emoji panel
ui::SetTabletModeShowEmojiKeyboardCallback(base::BindRepeating(
&VirtualKeyboardController::ForceShowKeyboardWithKeyset,
base::Unretained(this), input_method::ImeKeyset::kEmoji));
keyboard::KeyboardUIController::Get()->AddObserver(this);
}
VirtualKeyboardController::~VirtualKeyboardController() {
keyboard::KeyboardUIController::Get()->RemoveObserver(this);
if (Shell::Get()->tablet_mode_controller())
Shell::Get()->tablet_mode_controller()->RemoveObserver(this);
if (Shell::Get()->session_controller())
Shell::Get()->session_controller()->RemoveObserver(this);
ui::DeviceDataManager::GetInstance()->RemoveObserver(this);
// Reset the emoji panel callback
ui::SetShowEmojiKeyboardCallback(base::DoNothing());
}
void VirtualKeyboardController::ForceShowKeyboardWithKeyset(
input_method::ImeKeyset keyset) {
Shell::Get()->ime_controller()->OverrideKeyboardKeyset(
keyset, base::BindOnce(&VirtualKeyboardController::ForceShowKeyboard,
base::Unretained(this)));
}
void VirtualKeyboardController::ForceShowKeyboard() {
// If the virtual keyboard is enabled, show the keyboard directly.
auto* keyboard_controller = keyboard::KeyboardUIController::Get();
if (keyboard_controller->IsEnabled()) {
keyboard_controller->ShowKeyboard(false /* locked */);
return;
}
// Otherwise, temporarily enable the virtual keyboard until it is dismissed.
DCHECK(!keyboard::GetKeyboardEnabledFromShelf());
keyboard::SetKeyboardEnabledFromShelf(true);
keyboard_controller->ShowKeyboard(false);
}
void VirtualKeyboardController::OnTabletModeEventsBlockingChanged() {
UpdateKeyboardEnabled();
}
void VirtualKeyboardController::OnInputDeviceConfigurationChanged(
uint8_t input_device_types) {
if (input_device_types & (ui::InputDeviceEventObserver::kKeyboard |
ui::InputDeviceEventObserver::kTouchscreen)) {
UpdateDevices();
}
}
void VirtualKeyboardController::ToggleIgnoreExternalKeyboard() {
ignore_external_keyboard_ = !ignore_external_keyboard_;
UpdateKeyboardEnabled();
}
void VirtualKeyboardController::UpdateDevices() {
ui::DeviceDataManager* device_data_manager =
ui::DeviceDataManager::GetInstance();
touchscreens_ = device_data_manager->GetTouchscreenDevices();
// Checks for keyboards.
external_keyboards_.clear();
internal_keyboard_name_.reset();
for (const ui::InputDevice& device :
device_data_manager->GetKeyboardDevices()) {
ui::InputDeviceType type = device.type;
if (type == ui::InputDeviceType::INPUT_DEVICE_INTERNAL)
internal_keyboard_name_ = device.name;
if ((type == ui::InputDeviceType::INPUT_DEVICE_USB ||
(type == ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH &&
bluetooth_devices_observer_->IsConnectedBluetoothDevice(device))) &&
!device.suspected_keyboard_imposter) {
external_keyboards_.push_back(device);
}
}
// Update keyboard state.
UpdateKeyboardEnabled();
}
void VirtualKeyboardController::UpdateKeyboardEnabled() {
ignore_internal_keyboard_ = Shell::Get()
->tablet_mode_controller()
->AreInternalInputDeviceEventsBlocked();
bool is_internal_keyboard_active =
internal_keyboard_name_ && !ignore_internal_keyboard_;
keyboard::SetTouchKeyboardEnabled(
!is_internal_keyboard_active && !touchscreens_.empty() &&
(external_keyboards_.empty() || ignore_external_keyboard_));
Shell::Get()->system_tray_notifier()->NotifyVirtualKeyboardSuppressionChanged(
!is_internal_keyboard_active && !touchscreens_.empty() &&
!external_keyboards_.empty());
}
void VirtualKeyboardController::OnKeyboardHidden(bool is_temporary_hide) {
// The keyboard may temporarily hide (e.g. to change container behaviors).
// The keyset should not be reset in this case.
if (is_temporary_hide)
return;
// Post a task to reset the virtual keyboard to its original state.
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(ResetVirtualKeyboard));
}
void VirtualKeyboardController::OnActiveUserSessionChanged(
const AccountId& account_id) {
// Force on-screen keyboard to reset.
Shell::Get()->keyboard_controller()->RebuildKeyboardIfEnabled();
}
void VirtualKeyboardController::OnBluetoothAdapterOrDeviceChanged(
device::BluetoothDevice* device) {
// We only care about keyboard type bluetooth device change.
if (!device ||
device->GetDeviceType() == device::BluetoothDeviceType::KEYBOARD ||
device->GetDeviceType() ==
device::BluetoothDeviceType::KEYBOARD_MOUSE_COMBO) {
UpdateDevices();
}
}
const std::optional<std::string>&
VirtualKeyboardController::GetInternalKeyboardName() const {
return internal_keyboard_name_;
}
const std::vector<ui::InputDevice>&
VirtualKeyboardController::GetExternalKeyboards() const {
return external_keyboards_;
}
const std::vector<ui::TouchscreenDevice>&
VirtualKeyboardController::GetTouchscreens() const {
return touchscreens_;
}
bool VirtualKeyboardController::IsInternalKeyboardIgnored() const {
return ignore_internal_keyboard_;
}
bool VirtualKeyboardController::IsExternalKeyboardIgnored() const {
return ignore_external_keyboard_;
}
} // namespace ash
|