| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 <gdk/gdkkeysyms.h> | |
| 6 | |
| 7 #include "testing/gtest/include/gtest/gtest.h" | |
| 8 #include "ui/gfx/rect.h" | |
| 9 #include "ui/base/models/accelerator.h" | |
| 10 #include "views/focus/accelerator_handler.h" | |
| 11 #include "views/focus/focus_manager.h" | |
| 12 #include "views/view.h" | |
| 13 #include "views/widget/widget.h" | |
| 14 #include "views/widget/widget_delegate.h" | |
| 15 | |
| 16 namespace views { | |
| 17 | |
| 18 class AcceleratorHandlerGtkTest | |
| 19 : public testing::Test, | |
| 20 public WidgetDelegate, | |
| 21 public ui::AcceleratorTarget { | |
| 22 public: | |
| 23 AcceleratorHandlerGtkTest() | |
| 24 : kMenuAccelerator(ui::VKEY_MENU, false, false, false), | |
| 25 kHomepageAccelerator(ui::VKEY_HOME, false, false, true), | |
| 26 content_view_(NULL) { | |
| 27 } | |
| 28 | |
| 29 virtual void SetUp() { | |
| 30 window_ = Widget::CreateWindowWithBounds(this, gfx::Rect(0, 0, 500, 500)); | |
| 31 window_->Show(); | |
| 32 FocusManager* focus_manager = window_->GetFocusManager(); | |
| 33 focus_manager->RegisterAccelerator(kMenuAccelerator, this); | |
| 34 focus_manager->RegisterAccelerator(kHomepageAccelerator, this); | |
| 35 menu_pressed_ = false; | |
| 36 home_pressed_ = false; | |
| 37 } | |
| 38 | |
| 39 virtual void TearDown() { | |
| 40 window_->Close(); | |
| 41 | |
| 42 // Flush the message loop to make application verifiers happy. | |
| 43 message_loop_.RunAllPending(); | |
| 44 } | |
| 45 | |
| 46 GdkEventKey CreateKeyEvent(GdkEventType type, guint keyval, guint state) { | |
| 47 GdkEventKey evt; | |
| 48 memset(&evt, 0, sizeof(evt)); | |
| 49 evt.type = type; | |
| 50 evt.keyval = keyval; | |
| 51 // The keyval won't be a "correct" hardware keycode for any real hardware, | |
| 52 // but the code should never depend on exact hardware keycodes, just the | |
| 53 // fact that the code for presses and releases of the same key match. | |
| 54 evt.hardware_keycode = keyval; | |
| 55 evt.state = state; | |
| 56 GtkWidget* widget = GTK_WIDGET(window_->GetNativeWindow()); | |
| 57 evt.window = widget->window; | |
| 58 return evt; | |
| 59 } | |
| 60 | |
| 61 // AcceleratorTarget implementation. | |
| 62 virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) { | |
| 63 if (accelerator == kMenuAccelerator) | |
| 64 menu_pressed_ = true; | |
| 65 else if (accelerator == kHomepageAccelerator) | |
| 66 home_pressed_ = true; | |
| 67 return true; | |
| 68 } | |
| 69 | |
| 70 // WidgetDelegate Implementation. | |
| 71 virtual View* GetContentsView() { | |
| 72 if (!content_view_) | |
| 73 content_view_ = new View(); | |
| 74 return content_view_; | |
| 75 } | |
| 76 virtual const views::Widget* GetWidget() const { | |
| 77 return content_view_->GetWidget(); | |
| 78 } | |
| 79 virtual views::Widget* GetWidget() { | |
| 80 return content_view_->GetWidget(); | |
| 81 } | |
| 82 | |
| 83 virtual void InitContentView() { | |
| 84 } | |
| 85 | |
| 86 protected: | |
| 87 bool menu_pressed_; | |
| 88 bool home_pressed_; | |
| 89 | |
| 90 private: | |
| 91 ui::Accelerator kMenuAccelerator; | |
| 92 ui::Accelerator kHomepageAccelerator; | |
| 93 Widget* window_; | |
| 94 View* content_view_; | |
| 95 MessageLoopForUI message_loop_; | |
| 96 DISALLOW_COPY_AND_ASSIGN(AcceleratorHandlerGtkTest); | |
| 97 }; | |
| 98 | |
| 99 // Test that the homepage accelerator (Alt+Home) is activated on key down | |
| 100 // and that the menu accelerator (Alt) is never activated. | |
| 101 TEST_F(AcceleratorHandlerGtkTest, TestHomepageAccelerator) { | |
| 102 AcceleratorHandler handler; | |
| 103 GdkEventKey evt; | |
| 104 | |
| 105 ASSERT_FALSE(menu_pressed_); | |
| 106 ASSERT_FALSE(home_pressed_); | |
| 107 | |
| 108 evt = CreateKeyEvent(GDK_KEY_PRESS, GDK_Alt_L, 0); | |
| 109 EXPECT_TRUE(handler.Dispatch(reinterpret_cast<GdkEvent*>(&evt))); | |
| 110 | |
| 111 ASSERT_FALSE(menu_pressed_); | |
| 112 ASSERT_FALSE(home_pressed_); | |
| 113 | |
| 114 evt = CreateKeyEvent(GDK_KEY_PRESS, GDK_Home, GDK_MOD1_MASK); | |
| 115 EXPECT_TRUE(handler.Dispatch(reinterpret_cast<GdkEvent*>(&evt))); | |
| 116 | |
| 117 ASSERT_FALSE(menu_pressed_); | |
| 118 ASSERT_TRUE(home_pressed_); | |
| 119 | |
| 120 evt = CreateKeyEvent(GDK_KEY_RELEASE, GDK_Home, GDK_MOD1_MASK); | |
| 121 EXPECT_TRUE(handler.Dispatch(reinterpret_cast<GdkEvent*>(&evt))); | |
| 122 evt = CreateKeyEvent(GDK_KEY_RELEASE, GDK_Alt_L, 0); | |
| 123 EXPECT_TRUE(handler.Dispatch(reinterpret_cast<GdkEvent*>(&evt))); | |
| 124 | |
| 125 ASSERT_FALSE(menu_pressed_); | |
| 126 ASSERT_TRUE(home_pressed_); | |
| 127 } | |
| 128 | |
| 129 // Test that the menu accelerator is activated on key up and not key down. | |
| 130 TEST_F(AcceleratorHandlerGtkTest, TestMenuAccelerator) { | |
| 131 AcceleratorHandler handler; | |
| 132 GdkEventKey evt; | |
| 133 | |
| 134 ASSERT_FALSE(menu_pressed_); | |
| 135 | |
| 136 evt = CreateKeyEvent(GDK_KEY_PRESS, GDK_Alt_L, 0); | |
| 137 EXPECT_TRUE(handler.Dispatch(reinterpret_cast<GdkEvent*>(&evt))); | |
| 138 | |
| 139 ASSERT_FALSE(menu_pressed_); | |
| 140 | |
| 141 evt = CreateKeyEvent(GDK_KEY_RELEASE, GDK_Alt_L, 0); | |
| 142 EXPECT_TRUE(handler.Dispatch(reinterpret_cast<GdkEvent*>(&evt))); | |
| 143 | |
| 144 ASSERT_TRUE(menu_pressed_); | |
| 145 } | |
| 146 | |
| 147 // Test that the menu accelerator isn't confused by the interaction of the | |
| 148 // Alt and Shift keys. Try the following sequence on Linux: | |
| 149 // Press Alt | |
| 150 // Press Shift | |
| 151 // Release Alt | |
| 152 // Release Shift | |
| 153 // The key codes for pressing Alt and releasing Alt are different! This | |
| 154 // caused a bug in a previous version of the code, which is now fixed by | |
| 155 // keeping track of hardware keycodes, which are consistent. | |
| 156 TEST_F(AcceleratorHandlerGtkTest, TestAltShiftInteraction) { | |
| 157 AcceleratorHandler handler; | |
| 158 GdkEventKey evt; | |
| 159 | |
| 160 ASSERT_FALSE(menu_pressed_); | |
| 161 | |
| 162 // Press Shift. | |
| 163 evt = CreateKeyEvent(GDK_KEY_PRESS, GDK_Shift_L, 0); | |
| 164 evt.hardware_keycode = 0x32; | |
| 165 EXPECT_TRUE(handler.Dispatch(reinterpret_cast<GdkEvent*>(&evt))); | |
| 166 // Press Alt - but GDK calls this Meta when Shift is also down. | |
| 167 evt = CreateKeyEvent(GDK_KEY_PRESS, GDK_Meta_L, 0); | |
| 168 evt.hardware_keycode = 0x40; | |
| 169 EXPECT_TRUE(handler.Dispatch(reinterpret_cast<GdkEvent*>(&evt))); | |
| 170 | |
| 171 // Release Shift. | |
| 172 evt = CreateKeyEvent(GDK_KEY_RELEASE, GDK_Shift_L, 0); | |
| 173 evt.hardware_keycode = 0x32; | |
| 174 EXPECT_TRUE(handler.Dispatch(reinterpret_cast<GdkEvent*>(&evt))); | |
| 175 // Release Alt - with Shift not down, the keyval is now Alt, but | |
| 176 // the hardware keycode is unchanged. | |
| 177 evt = CreateKeyEvent(GDK_KEY_RELEASE, GDK_Alt_L, 0); | |
| 178 evt.hardware_keycode = 0x40; | |
| 179 EXPECT_TRUE(handler.Dispatch(reinterpret_cast<GdkEvent*>(&evt))); | |
| 180 | |
| 181 ASSERT_FALSE(menu_pressed_); | |
| 182 | |
| 183 // Press Alt by itself. | |
| 184 evt = CreateKeyEvent(GDK_KEY_PRESS, GDK_Alt_L, 0); | |
| 185 evt.hardware_keycode = 0x40; | |
| 186 EXPECT_TRUE(handler.Dispatch(reinterpret_cast<GdkEvent*>(&evt))); | |
| 187 | |
| 188 // This line fails if we don't keep track of hardware keycodes. | |
| 189 ASSERT_FALSE(menu_pressed_); | |
| 190 | |
| 191 // Release Alt - now this should trigger the menu shortcut. | |
| 192 evt = CreateKeyEvent(GDK_KEY_RELEASE, GDK_Alt_L, 0); | |
| 193 evt.hardware_keycode = 0x40; | |
| 194 EXPECT_TRUE(handler.Dispatch(reinterpret_cast<GdkEvent*>(&evt))); | |
| 195 | |
| 196 ASSERT_TRUE(menu_pressed_); | |
| 197 } | |
| 198 | |
| 199 } // namespace views | |
| OLD | NEW |