// Copyright 2015 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 "ash/shell.h" #include "base/macros.h" #include "components/exo/buffer.h" #include "components/exo/keyboard.h" #include "components/exo/keyboard_delegate.h" #include "components/exo/shell_surface.h" #include "components/exo/surface.h" #include "components/exo/test/exo_test_base.h" #include "components/exo/test/exo_test_helper.h" #include "testing/gmock/include/gmock/gmock.h" #include "ui/aura/client/focus_client.h" #include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/test/event_generator.h" namespace exo { namespace { using KeyboardTest = test::ExoTestBase; class MockKeyboardDelegate : public KeyboardDelegate { public: MockKeyboardDelegate() {} // Overridden from KeyboardDelegate: MOCK_METHOD1(OnKeyboardDestroying, void(Keyboard*)); MOCK_CONST_METHOD1(CanAcceptKeyboardEventsForSurface, bool(Surface*)); MOCK_METHOD2(OnKeyboardEnter, void(Surface*, const std::vector&)); MOCK_METHOD1(OnKeyboardLeave, void(Surface*)); MOCK_METHOD3(OnKeyboardKey, void(base::TimeDelta, ui::DomCode, bool)); MOCK_METHOD1(OnKeyboardModifiers, void(int)); }; TEST_F(KeyboardTest, OnKeyboardEnter) { scoped_ptr surface(new Surface); scoped_ptr shell_surface(new ShellSurface(surface.get())); gfx::Size buffer_size(10, 10); scoped_ptr buffer( new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size))); surface->Attach(buffer.get()); surface->Commit(); aura::client::FocusClient* focus_client = aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow()); focus_client->FocusWindow(surface.get()); // Keyboard should try to set initial focus to surface. MockKeyboardDelegate delegate; EXPECT_CALL(delegate, CanAcceptKeyboardEventsForSurface(surface.get())) .WillOnce(testing::Return(false)); scoped_ptr keyboard(new Keyboard(&delegate)); ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow()); generator.PressKey(ui::VKEY_A, 0); EXPECT_CALL(delegate, CanAcceptKeyboardEventsForSurface(surface.get())) .WillOnce(testing::Return(true)); ui::DomCode expected_pressed_keys[] = {ui::DomCode::US_A}; EXPECT_CALL(delegate, OnKeyboardModifiers(0)); EXPECT_CALL(delegate, OnKeyboardEnter(surface.get(), std::vector( expected_pressed_keys, expected_pressed_keys + arraysize(expected_pressed_keys)))); focus_client->FocusWindow(nullptr); focus_client->FocusWindow(surface.get()); // Surface should maintain keyboard focus when moved to top-level window. focus_client->FocusWindow(surface->GetToplevelWindow()); EXPECT_CALL(delegate, OnKeyboardDestroying(keyboard.get())); keyboard.reset(); } TEST_F(KeyboardTest, OnKeyboardLeave) { scoped_ptr surface(new Surface); scoped_ptr shell_surface(new ShellSurface(surface.get())); gfx::Size buffer_size(10, 10); scoped_ptr buffer( new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size))); surface->Attach(buffer.get()); surface->Commit(); aura::client::FocusClient* focus_client = aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow()); focus_client->FocusWindow(nullptr); MockKeyboardDelegate delegate; scoped_ptr keyboard(new Keyboard(&delegate)); EXPECT_CALL(delegate, CanAcceptKeyboardEventsForSurface(surface.get())) .WillOnce(testing::Return(true)); EXPECT_CALL(delegate, OnKeyboardModifiers(0)); EXPECT_CALL(delegate, OnKeyboardEnter(surface.get(), std::vector())); focus_client->FocusWindow(surface.get()); EXPECT_CALL(delegate, OnKeyboardLeave(surface.get())); focus_client->FocusWindow(nullptr); EXPECT_CALL(delegate, OnKeyboardDestroying(keyboard.get())); keyboard.reset(); } TEST_F(KeyboardTest, OnKeyboardKey) { scoped_ptr surface(new Surface); scoped_ptr shell_surface(new ShellSurface(surface.get())); gfx::Size buffer_size(10, 10); scoped_ptr buffer( new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size))); surface->Attach(buffer.get()); surface->Commit(); aura::client::FocusClient* focus_client = aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow()); focus_client->FocusWindow(nullptr); MockKeyboardDelegate delegate; scoped_ptr keyboard(new Keyboard(&delegate)); EXPECT_CALL(delegate, CanAcceptKeyboardEventsForSurface(surface.get())) .WillOnce(testing::Return(true)); EXPECT_CALL(delegate, OnKeyboardModifiers(0)); EXPECT_CALL(delegate, OnKeyboardEnter(surface.get(), std::vector())); focus_client->FocusWindow(surface.get()); ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow()); // This should only generate one press event for KEY_A. EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::US_A, true)); generator.PressKey(ui::VKEY_A, 0); generator.PressKey(ui::VKEY_A, 0); generator.ReleaseKey(ui::VKEY_B, 0); // This should only generate one release event for KEY_A. EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::US_A, false)); generator.ReleaseKey(ui::VKEY_A, 0); generator.ReleaseKey(ui::VKEY_A, 0); EXPECT_CALL(delegate, OnKeyboardDestroying(keyboard.get())); keyboard.reset(); } TEST_F(KeyboardTest, OnKeyboardModifiers) { scoped_ptr surface(new Surface); scoped_ptr shell_surface(new ShellSurface(surface.get())); gfx::Size buffer_size(10, 10); scoped_ptr buffer( new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size))); surface->Attach(buffer.get()); surface->Commit(); aura::client::FocusClient* focus_client = aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow()); focus_client->FocusWindow(nullptr); MockKeyboardDelegate delegate; scoped_ptr keyboard(new Keyboard(&delegate)); EXPECT_CALL(delegate, CanAcceptKeyboardEventsForSurface(surface.get())) .WillOnce(testing::Return(true)); EXPECT_CALL(delegate, OnKeyboardModifiers(0)); EXPECT_CALL(delegate, OnKeyboardEnter(surface.get(), std::vector())); focus_client->FocusWindow(surface.get()); ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow()); // This should generate a modifier event. EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::US_A, true)); EXPECT_CALL(delegate, OnKeyboardModifiers(ui::EF_SHIFT_DOWN)); generator.PressKey(ui::VKEY_A, ui::EF_SHIFT_DOWN); // This should generate another modifier event. EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::US_B, true)); EXPECT_CALL(delegate, OnKeyboardModifiers(ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN)); generator.PressKey(ui::VKEY_B, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN); // This should generate a third modifier event. EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::US_B, false)); EXPECT_CALL(delegate, OnKeyboardModifiers(0)); generator.ReleaseKey(ui::VKEY_B, 0); EXPECT_CALL(delegate, OnKeyboardDestroying(keyboard.get())); keyboard.reset(); } } // namespace } // namespace exo