Home | History | Annotate | Download | only in keyboard
      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.
      4 
      5 #include "ui/keyboard/keyboard_controller.h"
      6 
      7 #include "ui/aura/layout_manager.h"
      8 #include "ui/aura/window.h"
      9 #include "ui/aura/window_delegate.h"
     10 #include "ui/base/hit_test.h"
     11 #include "ui/base/ime/input_method.h"
     12 #include "ui/base/ime/text_input_client.h"
     13 #include "ui/base/ime/text_input_type.h"
     14 #include "ui/gfx/path.h"
     15 #include "ui/gfx/rect.h"
     16 #include "ui/gfx/skia_util.h"
     17 #include "ui/keyboard/keyboard_controller_observer.h"
     18 #include "ui/keyboard/keyboard_controller_proxy.h"
     19 
     20 namespace {
     21 
     22 gfx::Rect KeyboardBoundsFromWindowBounds(const gfx::Rect& window_bounds) {
     23   const float kKeyboardHeightRatio = 0.3f;
     24   return gfx::Rect(
     25       window_bounds.x(),
     26       window_bounds.y() + window_bounds.height() * (1 - kKeyboardHeightRatio),
     27       window_bounds.width(),
     28       window_bounds.height() * kKeyboardHeightRatio);
     29 }
     30 
     31 // The KeyboardWindowDelegate makes sure the keyboard-window does not get focus.
     32 // This is necessary to make sure that the synthetic key-events reach the target
     33 // window.
     34 // The delegate deletes itself when the window is destroyed.
     35 class KeyboardWindowDelegate : public aura::WindowDelegate {
     36  public:
     37   KeyboardWindowDelegate() {}
     38   virtual ~KeyboardWindowDelegate() {}
     39 
     40  private:
     41   // Overridden from aura::WindowDelegate:
     42   virtual gfx::Size GetMinimumSize() const OVERRIDE { return gfx::Size(); }
     43   virtual gfx::Size GetMaximumSize() const OVERRIDE { return gfx::Size(); }
     44   virtual void OnBoundsChanged(const gfx::Rect& old_bounds,
     45                                const gfx::Rect& new_bounds) OVERRIDE {
     46     bounds_ = new_bounds;
     47   }
     48   virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE {
     49     return gfx::kNullCursor;
     50   }
     51   virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE {
     52     return HTNOWHERE;
     53   }
     54   virtual bool ShouldDescendIntoChildForEventHandling(
     55       aura::Window* child,
     56       const gfx::Point& location) OVERRIDE {
     57     return true;
     58   }
     59   virtual bool CanFocus() OVERRIDE { return false; }
     60   virtual void OnCaptureLost() OVERRIDE {}
     61   virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {}
     62   virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {}
     63   virtual void OnWindowDestroying() OVERRIDE {}
     64   virtual void OnWindowDestroyed() OVERRIDE { delete this; }
     65   virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE {}
     66   virtual bool HasHitTestMask() const OVERRIDE { return true; }
     67   virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {
     68     gfx::Rect keyboard_bounds = KeyboardBoundsFromWindowBounds(bounds_);
     69     mask->addRect(RectToSkRect(keyboard_bounds));
     70   }
     71   virtual scoped_refptr<ui::Texture> CopyTexture() OVERRIDE { return NULL; }
     72 
     73   gfx::Rect bounds_;
     74   DISALLOW_COPY_AND_ASSIGN(KeyboardWindowDelegate);
     75 };
     76 
     77 }  // namespace
     78 
     79 namespace keyboard {
     80 
     81 // LayoutManager for the virtual keyboard container.  Manages a single window
     82 // (the virtual keyboard) and keeps it positioned at the bottom of the
     83 // owner window.
     84 class KeyboardLayoutManager : public aura::LayoutManager {
     85  public:
     86   KeyboardLayoutManager(aura::Window* container)
     87       : container_(container), keyboard_(NULL) {
     88     CHECK(container_);
     89   }
     90 
     91   // Overridden from aura::LayoutManager
     92   virtual void OnWindowResized() OVERRIDE {
     93     if (!keyboard_)
     94       return;
     95     SetChildBoundsDirect(keyboard_,
     96                          KeyboardBoundsFromWindowBounds(container_->bounds()));
     97   }
     98   virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {
     99     DCHECK(!keyboard_);
    100     keyboard_ = child;
    101   }
    102   virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {}
    103   virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {}
    104   virtual void OnChildWindowVisibilityChanged(aura::Window* child,
    105                                               bool visible) OVERRIDE {}
    106   virtual void SetChildBounds(aura::Window* child,
    107                               const gfx::Rect& requested_bounds) OVERRIDE {
    108     // Drop these: the size should only be set in OnWindowResized.
    109   }
    110 
    111  private:
    112   aura::Window* container_;
    113   aura::Window* keyboard_;
    114 
    115   DISALLOW_COPY_AND_ASSIGN(KeyboardLayoutManager);
    116 };
    117 
    118 KeyboardController::KeyboardController(KeyboardControllerProxy* proxy)
    119     : proxy_(proxy),
    120       container_(NULL),
    121       input_method_(NULL) {
    122   CHECK(proxy);
    123   input_method_ = proxy_->GetInputMethod();
    124   input_method_->AddObserver(this);
    125 }
    126 
    127 KeyboardController::~KeyboardController() {
    128   if (container_)
    129     container_->RemoveObserver(this);
    130   if (input_method_)
    131     input_method_->RemoveObserver(this);
    132 }
    133 
    134 aura::Window* KeyboardController::GetContainerWindow() {
    135   if (!container_) {
    136     container_ = new aura::Window(new KeyboardWindowDelegate());
    137     container_->SetName("KeyboardContainer");
    138     container_->Init(ui::LAYER_NOT_DRAWN);
    139     container_->AddObserver(this);
    140     container_->SetLayoutManager(new KeyboardLayoutManager(container_));
    141   }
    142   return container_;
    143 }
    144 
    145 void KeyboardController::AddObserver(KeyboardControllerObserver* observer) {
    146   observer_list_.AddObserver(observer);
    147 }
    148 
    149 void KeyboardController::RemoveObserver(KeyboardControllerObserver* observer) {
    150   observer_list_.RemoveObserver(observer);
    151 }
    152 
    153 void KeyboardController::OnWindowHierarchyChanged(
    154     const HierarchyChangeParams& params) {
    155   if (params.new_parent && params.target == container_)
    156     OnTextInputStateChanged(proxy_->GetInputMethod()->GetTextInputClient());
    157 }
    158 
    159 void KeyboardController::OnWindowDestroying(aura::Window* window) {
    160   DCHECK_EQ(container_, window);
    161   container_ = NULL;
    162 }
    163 
    164 void KeyboardController::OnTextInputStateChanged(
    165     const ui::TextInputClient* client) {
    166   if (!container_)
    167     return;
    168 
    169   bool was_showing = container_->IsVisible();
    170   bool should_show = was_showing;
    171   if (!client || client->GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) {
    172     should_show = false;
    173   } else {
    174     if (container_->children().empty()) {
    175       aura::Window* keyboard = proxy_->GetKeyboardWindow();
    176       keyboard->Show();
    177       container_->AddChild(keyboard);
    178       container_->layout_manager()->OnWindowResized();
    179     }
    180     container_->parent()->StackChildAtTop(container_);
    181     should_show = true;
    182   }
    183 
    184   if (was_showing != should_show) {
    185     gfx::Rect new_bounds(
    186         should_show ? container_->children()[0]->bounds() : gfx::Rect());
    187 
    188     FOR_EACH_OBSERVER(
    189         KeyboardControllerObserver,
    190         observer_list_,
    191         OnKeyboardBoundsChanging(new_bounds));
    192 
    193     if (should_show)
    194       proxy_->ShowKeyboardContainer(container_);
    195     else
    196       proxy_->HideKeyboardContainer(container_);
    197   }
    198 
    199   // TODO(bryeung): whenever the TextInputClient changes we need to notify the
    200   // keyboard (with the TextInputType) so that it can reset it's state (e.g.
    201   // abandon compositions in progress)
    202 }
    203 
    204 void KeyboardController::OnInputMethodDestroyed(
    205     const ui::InputMethod* input_method) {
    206   DCHECK_EQ(input_method_, input_method);
    207   input_method_ = NULL;
    208 }
    209 
    210 }  // namespace keyboard
    211