|  | // Copyright 2020 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 "content/browser/renderer_host/virtual_keyboard_controller_win.h" | 
|  |  | 
|  | #include "base/trace_event/trace_event.h" | 
|  | #include "content/browser/renderer_host/render_widget_host_view_aura.h" | 
|  | #include "ui/base/ime/input_method.h" | 
|  | #include "ui/base/ime/input_method_keyboard_controller.h" | 
|  | #include "ui/base/ime/mojom/text_input_state.mojom.h" | 
|  | #include "ui/events/event_utils.h" | 
|  | #include "ui/gfx/geometry/rect.h" | 
|  |  | 
|  | namespace content { | 
|  |  | 
|  | VirtualKeyboardControllerWin::VirtualKeyboardControllerWin( | 
|  | RenderWidgetHostViewAura* host_view, | 
|  | ui::InputMethod* input_method) | 
|  | : host_view_(host_view), input_method_(input_method) { | 
|  | host_view_->SetInsets(gfx::Insets()); | 
|  | } | 
|  |  | 
|  | VirtualKeyboardControllerWin::~VirtualKeyboardControllerWin() { | 
|  | if (observers_registered_) { | 
|  | // De-register the input pane observers. | 
|  | if (auto* controller = input_method_->GetInputMethodKeyboardController()) | 
|  | controller->RemoveObserver(this); | 
|  | } | 
|  | } | 
|  |  | 
|  | void VirtualKeyboardControllerWin::HideAndNotifyKeyboardInset() { | 
|  | if (auto* controller = input_method_->GetInputMethodKeyboardController()) { | 
|  | if (virtual_keyboard_shown_) { | 
|  | // If the VK is already showing, then dismiss it first. | 
|  | controller->DismissVirtualKeyboard(); | 
|  | // Should also scroll the content into view after the VK dismisses. | 
|  | OnKeyboardHidden(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void VirtualKeyboardControllerWin::OnKeyboardVisible( | 
|  | const gfx::Rect& keyboard_rect) { | 
|  | TRACE_EVENT0("vk", "VirtualKeyboardControllerWin::OnKeyboardVisible"); | 
|  | // If the software input panel (SIP) is manually raised by the user, the flag | 
|  | // should be set so we don't call TryShow API again. | 
|  | virtual_keyboard_shown_ = true; | 
|  | if (!host_view_->ShouldVirtualKeyboardOverlayContent()) { | 
|  | host_view_->SetInsets(gfx::Insets( | 
|  | 0, 0, keyboard_rect.IsEmpty() ? 0 : keyboard_rect.height(), 0)); | 
|  | } else { | 
|  | host_view_->NotifyVirtualKeyboardOverlayRect(keyboard_rect); | 
|  | } | 
|  | } | 
|  |  | 
|  | void VirtualKeyboardControllerWin::OnKeyboardHidden() { | 
|  | TRACE_EVENT0("vk", "VirtualKeyboardControllerWin::OnKeyboardHidden"); | 
|  | // If the software input panel (SIP) is manually closed by the user, the flag | 
|  | // should be reset so we don't call TryHide API again. Also, | 
|  | // next time user taps on an editable element after manually dismissing the | 
|  | // keyboard, this flag is used to determine whether TryShow needs to be | 
|  | // called or not. Calling TryShow/TryHide multiple times leads to SIP | 
|  | // flickering. | 
|  | virtual_keyboard_shown_ = false; | 
|  | if (!host_view_->ShouldVirtualKeyboardOverlayContent()) { | 
|  | // Restore the viewport. | 
|  | host_view_->SetInsets(gfx::Insets()); | 
|  | } else { | 
|  | host_view_->NotifyVirtualKeyboardOverlayRect(gfx::Rect()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void VirtualKeyboardControllerWin::ShowVirtualKeyboard() { | 
|  | TRACE_EVENT0("vk", "VirtualKeyboardControllerWin::ShowVirtualKeyboard"); | 
|  | if (auto* controller = input_method_->GetInputMethodKeyboardController()) { | 
|  | if (!virtual_keyboard_shown_) { | 
|  | virtual_keyboard_shown_ = true; | 
|  | input_method_->ShowVirtualKeyboardIfEnabled(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void VirtualKeyboardControllerWin::HideVirtualKeyboard() { | 
|  | TRACE_EVENT0("vk", "VirtualKeyboardControllerWin::HideVirtualKeyboard"); | 
|  | if (auto* controller = input_method_->GetInputMethodKeyboardController()) { | 
|  | if (virtual_keyboard_shown_) { | 
|  | virtual_keyboard_shown_ = false; | 
|  | controller->DismissVirtualKeyboard(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void VirtualKeyboardControllerWin::UpdateTextInputState( | 
|  | const ui::mojom::TextInputState* state) { | 
|  | // Conditions to show the VK: | 
|  | // 1. User has to interact with the editable element. | 
|  | // 2. Pointer type has to be either touch or pen. | 
|  | // 3. If virtualkeyboardpolicy is manual, leave the SIP in its current state - | 
|  | //    script authors need to call show() or hide() explicitly to trigger SIP | 
|  | //    actions. | 
|  | // 4. If virtualkeyboardpolicy is auto, show the SIP. | 
|  | // If there are no keyboard controllers or the pointer type is neither pen or | 
|  | // touch, then don't change the state of the keyboard. | 
|  | auto* controller = input_method_->GetInputMethodKeyboardController(); | 
|  | is_manual_policy_ = | 
|  | state->vk_policy == ui::mojom::VirtualKeyboardPolicy::MANUAL; | 
|  | if (!controller || | 
|  | !(IsPointerTypeValidForVirtualKeyboard() || is_manual_policy_) || | 
|  | !host_view_->host()->GetView() || !host_view_->host()->delegate()) { | 
|  | return; | 
|  | } | 
|  | // Register the observers if the pointer type is pen/touch. | 
|  | if (!observers_registered_) { | 
|  | controller->AddObserver(this); | 
|  | observers_registered_ = true; | 
|  | } | 
|  | if (state->show_ime_if_needed && | 
|  | state->vk_policy == ui::mojom::VirtualKeyboardPolicy::AUTO) { | 
|  | ShowVirtualKeyboard(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (is_manual_policy_) { | 
|  | switch (state->last_vk_visibility_request) { | 
|  | case ui::mojom::VirtualKeyboardVisibilityRequest::SHOW: | 
|  | if (host_view_->FocusedFrameHasStickyActivation()) | 
|  | ShowVirtualKeyboard(); | 
|  | break; | 
|  | case ui::mojom::VirtualKeyboardVisibilityRequest::HIDE: | 
|  | HideVirtualKeyboard(); | 
|  | break; | 
|  | default: | 
|  | // Don't change the state of the VK. | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void VirtualKeyboardControllerWin::FocusedNodeChanged(bool is_editable) { | 
|  | if (!is_editable) { | 
|  | HideVirtualKeyboard(); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool VirtualKeyboardControllerWin::IsPointerTypeValidForVirtualKeyboard() | 
|  | const { | 
|  | return (host_view_->GetLastPointerType() == ui::EventPointerType::kTouch || | 
|  | host_view_->GetLastPointerType() == ui::EventPointerType::kPen); | 
|  | } | 
|  |  | 
|  | }  // namespace content |