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 |