Home | History | Annotate | Download | only in focus
      1 // Copyright (c) 2012 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/views/focus/focus_manager.h"
      6 
      7 #include "base/memory/scoped_ptr.h"
      8 #include "base/run_loop.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "ui/base/events/event.h"
     11 #include "ui/views/controls/button/label_button.h"
     12 #include "ui/views/focus/accelerator_handler.h"
     13 #include "ui/views/focus/focus_manager_test.h"
     14 #include "ui/views/widget/widget.h"
     15 
     16 namespace views {
     17 
     18 namespace {
     19 
     20 class MessageTrackingView : public View {
     21  public:
     22   MessageTrackingView() : accelerator_pressed_(false) {
     23   }
     24 
     25   void Reset() {
     26     accelerator_pressed_ = false;
     27     keys_pressed_.clear();
     28     keys_released_.clear();
     29   }
     30 
     31   const std::vector<ui::KeyboardCode>& keys_pressed() const {
     32     return keys_pressed_;
     33   }
     34 
     35   const std::vector<ui::KeyboardCode>& keys_released() const {
     36     return keys_released_;
     37   }
     38 
     39   bool accelerator_pressed() const {
     40     return accelerator_pressed_;
     41   }
     42 
     43   // Overridden from View:
     44   virtual bool OnKeyPressed(const ui::KeyEvent& e) OVERRIDE {
     45     keys_pressed_.push_back(e.key_code());
     46     return true;
     47   }
     48   virtual bool OnKeyReleased(const ui::KeyEvent& e) OVERRIDE {
     49     keys_released_.push_back(e.key_code());
     50     return true;
     51   }
     52   virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE {
     53     accelerator_pressed_ = true;
     54     return true;
     55   }
     56 
     57  private:
     58   bool accelerator_pressed_;
     59   std::vector<ui::KeyboardCode> keys_pressed_;
     60   std::vector<ui::KeyboardCode> keys_released_;
     61 
     62   DISALLOW_COPY_AND_ASSIGN(MessageTrackingView);
     63 };
     64 
     65 }  // namespace
     66 
     67 // Test that when activating/deactivating the top window, the focus is stored/
     68 // restored properly.
     69 TEST_F(FocusManagerTest, FocusStoreRestore) {
     70   // Simulate an activate, otherwise the deactivate isn't going to do anything.
     71   SimulateActivateWindow();
     72 
     73   LabelButton* button = new LabelButton(NULL, ASCIIToUTF16("Press me"));
     74   button->SetStyle(Button::STYLE_NATIVE_TEXTBUTTON);
     75   View* view = new View();
     76   view->set_focusable(true);
     77 
     78   GetContentsView()->AddChildView(button);
     79   button->SetBounds(10, 10, 200, 30);
     80   GetContentsView()->AddChildView(view);
     81   RunPendingMessages();
     82 
     83   TestFocusChangeListener listener;
     84   AddFocusChangeListener(&listener);
     85 
     86   view->RequestFocus();
     87   RunPendingMessages();
     88 
     89   // Required for VS2010: http://connect.microsoft.com/VisualStudio/feedback/details/520043/error-converting-from-null-to-a-pointer-type-in-std-pair
     90   views::View* null_view = NULL;
     91 
     92   // Deacivate the window, it should store its focus.
     93   SimulateDeactivateWindow();
     94   EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView());
     95   ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size()));
     96   EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, view));
     97   EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(view, null_view));
     98   listener.ClearFocusChanges();
     99 
    100   // Reactivate, focus should come-back to the previously focused view.
    101   SimulateActivateWindow();
    102   EXPECT_EQ(view, GetFocusManager()->GetFocusedView());
    103   ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size()));
    104   EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, view));
    105   listener.ClearFocusChanges();
    106 
    107   // Same test with a NativeControl.
    108   button->RequestFocus();
    109   SimulateDeactivateWindow();
    110   EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView());
    111   ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size()));
    112   EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(view, button));
    113   EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(button, null_view));
    114   listener.ClearFocusChanges();
    115 
    116   SimulateActivateWindow();
    117   EXPECT_EQ(button, GetFocusManager()->GetFocusedView());
    118   ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size()));
    119   EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, button));
    120   listener.ClearFocusChanges();
    121 
    122   /*
    123   // Now test that while the window is inactive we can change the focused view
    124   // (we do that in several places).
    125   SimulateDeactivateWindow();
    126   // TODO: would have to mock the window being inactive (with a TestWidgetWin
    127   //       that would return false on IsActive()).
    128   GetFocusManager()->SetFocusedView(view);
    129   ::SendMessage(window_->GetNativeWindow(), WM_ACTIVATE, WA_ACTIVE, NULL);
    130 
    131   EXPECT_EQ(view, GetFocusManager()->GetFocusedView());
    132   ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size()));
    133   EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(button, null_view));
    134   EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(null_view, view));
    135   */
    136 }
    137 
    138 // Test that the focus manager is created successfully for the first view
    139 // window parented to a native dialog.
    140 TEST_F(FocusManagerTest, CreationForNativeRoot) {
    141   // Create a window class.
    142   WNDCLASSEX class_ex;
    143   memset(&class_ex, 0, sizeof(class_ex));
    144   class_ex.cbSize = sizeof(WNDCLASSEX);
    145   class_ex.lpfnWndProc = &DefWindowProc;
    146   class_ex.lpszClassName = L"TestWindow";
    147   ATOM atom = RegisterClassEx(&class_ex);
    148   ASSERT_TRUE(atom);
    149 
    150   // Create a native dialog window.
    151   HWND hwnd = CreateWindowEx(0, class_ex.lpszClassName, NULL,
    152                              WS_OVERLAPPEDWINDOW, 0, 0, 200, 200,
    153                              NULL, NULL, NULL, NULL);
    154   ASSERT_TRUE(hwnd);
    155 
    156   // Create a view window parented to native dialog.
    157   scoped_ptr<Widget> widget1(new Widget);
    158   Widget::InitParams params(Widget::InitParams::TYPE_CONTROL);
    159   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    160   params.parent = hwnd;
    161   params.bounds = gfx::Rect(0, 0, 100, 100);
    162   params.top_level = true;  // This is top level in views hierarchy.
    163   widget1->Init(params);
    164 
    165   // Get the focus manager directly from the first window.  Should exist
    166   // because the first window is the root widget.
    167   views::FocusManager* focus_manager1 = widget1->GetFocusManager();
    168   EXPECT_TRUE(focus_manager1);
    169 
    170   // Create another view window parented to the first view window.
    171   scoped_ptr<Widget> widget2(new Widget);
    172   params.parent = widget1->GetNativeView();
    173   params.top_level = false;  // This is child widget.
    174   widget2->Init(params);
    175 
    176   // Access the shared focus manager directly from the second window.
    177   views::FocusManager* focus_manager2 = widget2->GetFocusManager();
    178   EXPECT_EQ(focus_manager2, focus_manager1);
    179 
    180   // Access the shared focus manager indirectly from the first window handle.
    181   gfx::NativeWindow native_window = widget1->GetNativeWindow();
    182   views::Widget* widget =
    183       views::Widget::GetWidgetForNativeWindow(native_window);
    184   EXPECT_EQ(widget->GetFocusManager(), focus_manager1);
    185 
    186   // Access the shared focus manager indirectly from the second window handle.
    187   native_window = widget2->GetNativeWindow();
    188   widget = views::Widget::GetWidgetForNativeWindow(native_window);
    189   EXPECT_EQ(widget->GetFocusManager(), focus_manager1);
    190 
    191   // Access the shared focus manager indirectly from the first view handle.
    192   gfx::NativeView native_view = widget1->GetNativeView();
    193   widget = views::Widget::GetTopLevelWidgetForNativeView(native_view);
    194   EXPECT_EQ(widget->GetFocusManager(), focus_manager1);
    195 
    196   // Access the shared focus manager indirectly from the second view handle.
    197   native_view = widget2->GetNativeView();
    198   widget = views::Widget::GetTopLevelWidgetForNativeView(native_view);
    199   EXPECT_EQ(widget->GetFocusManager(), focus_manager1);
    200 
    201   DestroyWindow(hwnd);
    202 }
    203 
    204 // Tests that the keyup messages are eaten for accelerators.
    205 // Windows-only, Windows is the only platform that handles accelerators in
    206 // AcceleratorHandler. NativeWidgetAura::OnKeyEvent handles them in other
    207 // configurations.
    208 TEST_F(FocusManagerTest, IgnoreKeyupForAccelerators) {
    209   FocusManager* focus_manager = GetFocusManager();
    210   MessageTrackingView* mtv = new MessageTrackingView();
    211   mtv->AddAccelerator(ui::Accelerator(ui::VKEY_0, ui::EF_NONE));
    212   mtv->AddAccelerator(ui::Accelerator(ui::VKEY_1, ui::EF_NONE));
    213   GetContentsView()->AddChildView(mtv);
    214   focus_manager->SetFocusedView(mtv);
    215 
    216   // First send a non-accelerator key sequence.
    217   PostKeyDown(ui::VKEY_9);
    218   PostKeyUp(ui::VKEY_9);
    219   AcceleratorHandler accelerator_handler;
    220   scoped_ptr<base::RunLoop> run_loop(new base::RunLoop(&accelerator_handler));
    221   run_loop->RunUntilIdle();
    222   // Make sure we get a key-up and key-down.
    223   ASSERT_EQ(1U, mtv->keys_pressed().size());
    224   EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[0]);
    225   ASSERT_EQ(1U, mtv->keys_released().size());
    226   EXPECT_EQ(ui::VKEY_9, mtv->keys_released()[0]);
    227   EXPECT_FALSE(mtv->accelerator_pressed());
    228   mtv->Reset();
    229 
    230   // Same thing with repeat and more than one key at once.
    231   PostKeyDown(ui::VKEY_9);
    232   PostKeyDown(ui::VKEY_9);
    233   PostKeyDown(ui::VKEY_8);
    234   PostKeyDown(ui::VKEY_9);
    235   PostKeyDown(ui::VKEY_7);
    236   PostKeyUp(ui::VKEY_9);
    237   PostKeyUp(ui::VKEY_7);
    238   PostKeyUp(ui::VKEY_8);
    239   run_loop.reset(new base::RunLoop(&accelerator_handler));
    240   run_loop->RunUntilIdle();
    241   // Make sure we get a key-up and key-down.
    242   ASSERT_EQ(5U, mtv->keys_pressed().size());
    243   EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[0]);
    244   EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[1]);
    245   EXPECT_EQ(ui::VKEY_8, mtv->keys_pressed()[2]);
    246   EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[3]);
    247   EXPECT_EQ(ui::VKEY_7, mtv->keys_pressed()[4]);
    248   ASSERT_EQ(3U, mtv->keys_released().size());
    249   EXPECT_EQ(ui::VKEY_9, mtv->keys_released()[0]);
    250   EXPECT_EQ(ui::VKEY_7, mtv->keys_released()[1]);
    251   EXPECT_EQ(ui::VKEY_8, mtv->keys_released()[2]);
    252   EXPECT_FALSE(mtv->accelerator_pressed());
    253   mtv->Reset();
    254 
    255   // Now send an accelerator key sequence.
    256   PostKeyDown(ui::VKEY_0);
    257   PostKeyUp(ui::VKEY_0);
    258   run_loop.reset(new base::RunLoop(&accelerator_handler));
    259   run_loop->RunUntilIdle();
    260   EXPECT_TRUE(mtv->keys_pressed().empty());
    261   EXPECT_TRUE(mtv->keys_released().empty());
    262   EXPECT_TRUE(mtv->accelerator_pressed());
    263   mtv->Reset();
    264 
    265   // Same thing with repeat and more than one key at once.
    266   PostKeyDown(ui::VKEY_0);
    267   PostKeyDown(ui::VKEY_1);
    268   PostKeyDown(ui::VKEY_1);
    269   PostKeyDown(ui::VKEY_0);
    270   PostKeyDown(ui::VKEY_0);
    271   PostKeyUp(ui::VKEY_1);
    272   PostKeyUp(ui::VKEY_0);
    273   run_loop.reset(new base::RunLoop(&accelerator_handler));
    274   run_loop->RunUntilIdle();
    275   EXPECT_TRUE(mtv->keys_pressed().empty());
    276   EXPECT_TRUE(mtv->keys_released().empty());
    277   EXPECT_TRUE(mtv->accelerator_pressed());
    278   mtv->Reset();
    279 }
    280 
    281 }  // namespace views
    282