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