• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2009 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 #include "chrome/browser/renderer_host/gtk_key_bindings_handler.h"
5 
6 #include <gdk/gdkkeysyms.h>
7 #include <string>
8 #include <utility>
9 #include <vector>
10 
11 #include "base/basictypes.h"
12 #include "base/file_util.h"
13 #include "base/logging.h"
14 #include "base/path_service.h"
15 #include "base/string_util.h"
16 #include "chrome/common/chrome_paths.h"
17 #include "content/common/edit_command.h"
18 #include "content/common/native_web_keyboard_event.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 
21 class GtkKeyBindingsHandlerTest : public testing::Test {
22  protected:
23   struct EditCommand {
24     const char* name;
25     const char* value;
26   };
27 
GtkKeyBindingsHandlerTest()28   GtkKeyBindingsHandlerTest()
29       : window_(gtk_window_new(GTK_WINDOW_TOPLEVEL)),
30         handler_(NULL) {
31     FilePath gtkrc;
32     PathService::Get(chrome::DIR_TEST_DATA, &gtkrc);
33     gtkrc = gtkrc.AppendASCII("gtk_key_bindings_test_gtkrc");
34 
35     gtk_rc_parse(gtkrc.value().c_str());
36 
37     GtkWidget* fixed = gtk_fixed_new();
38     handler_ = new GtkKeyBindingsHandler(fixed);
39     gtk_container_add(GTK_CONTAINER(window_), fixed);
40     gtk_widget_show(fixed);
41     gtk_widget_show(window_);
42   }
~GtkKeyBindingsHandlerTest()43   ~GtkKeyBindingsHandlerTest() {
44     gtk_widget_destroy(window_);
45     delete handler_;
46   }
47 
NewNativeWebKeyboardEvent(guint keyval,guint state)48   NativeWebKeyboardEvent NewNativeWebKeyboardEvent(guint keyval, guint state) {
49     GdkKeymap* keymap =
50         gdk_keymap_get_for_display(gtk_widget_get_display(window_));
51 
52     GdkKeymapKey *keys = NULL;
53     gint n_keys = 0;
54     if (gdk_keymap_get_entries_for_keyval(keymap, keyval, &keys, &n_keys)) {
55       GdkEventKey event;
56       event.type = GDK_KEY_PRESS;
57       event.window = NULL;
58       event.send_event = 0;
59       event.time = 0;
60       event.state = state;
61       event.keyval = keyval;
62       event.length = 0;
63       event.string = NULL;
64       event.hardware_keycode = keys[0].keycode;
65       event.group = keys[0].group;
66       event.is_modifier = 0;
67       g_free(keys);
68       return NativeWebKeyboardEvent(&event);
69     }
70     LOG(ERROR) << "Failed to create key event for keyval:" << keyval;
71     return NativeWebKeyboardEvent();
72   }
73 
TestKeyBinding(const NativeWebKeyboardEvent & event,const EditCommand expected_result[],size_t size)74   void TestKeyBinding(const NativeWebKeyboardEvent& event,
75                       const EditCommand expected_result[],
76                       size_t size) {
77     EditCommands result;
78     ASSERT_TRUE(handler_->Match(event, &result));
79     ASSERT_EQ(size, result.size());
80     for (size_t i = 0; i < size; ++i) {
81       ASSERT_STREQ(expected_result[i].name, result[i].name.c_str());
82       ASSERT_STREQ(expected_result[i].value, result[i].value.c_str());
83     }
84   }
85 
86  protected:
87   GtkWidget* window_;
88   GtkKeyBindingsHandler* handler_;
89 };
90 
TEST_F(GtkKeyBindingsHandlerTest,MoveCursor)91 TEST_F(GtkKeyBindingsHandlerTest, MoveCursor) {
92   static const EditCommand kEditCommands[] = {
93     // "move-cursor" (logical-positions, -2, 0)
94     { "MoveBackward", "" },
95     { "MoveBackward", "" },
96     // "move-cursor" (logical-positions, 2, 0)
97     { "MoveForward", "" },
98     { "MoveForward", "" },
99     // "move-cursor" (visual-positions, -1, 1)
100     { "MoveLeftAndModifySelection", "" },
101     // "move-cursor" (visual-positions, 1, 1)
102     { "MoveRightAndModifySelection", "" },
103     // "move-cursor" (words, -1, 0)
104     { "MoveWordBackward", "" },
105     // "move-cursor" (words, 1, 0)
106     { "MoveWordForward", "" },
107     // "move-cursor" (display-lines, -1, 0)
108     { "MoveUp", "" },
109     // "move-cursor" (display-lines, 1, 0)
110     { "MoveDown", "" },
111     // "move-cursor" (display-line-ends, -1, 0)
112     { "MoveToBeginningOfLine", "" },
113     // "move-cursor" (display-line-ends, 1, 0)
114     { "MoveToEndOfLine", "" },
115     // "move-cursor" (paragraph-ends, -1, 0)
116     { "MoveToBeginningOfParagraph", "" },
117     // "move-cursor" (paragraph-ends, 1, 0)
118     { "MoveToEndOfParagraph", "" },
119     // "move-cursor" (pages, -1, 0)
120     { "MovePageUp", "" },
121     // "move-cursor" (pages, 1, 0)
122     { "MovePageDown", "" },
123     // "move-cursor" (buffer-ends, -1, 0)
124     { "MoveToBeginningOfDocument", "" },
125     // "move-cursor" (buffer-ends, 1, 0)
126     { "MoveToEndOfDocument", "" }
127   };
128 
129   TestKeyBinding(NewNativeWebKeyboardEvent(GDK_1, GDK_CONTROL_MASK),
130                  kEditCommands, arraysize(kEditCommands));
131 }
132 
TEST_F(GtkKeyBindingsHandlerTest,DeleteFromCursor)133 TEST_F(GtkKeyBindingsHandlerTest, DeleteFromCursor) {
134   static const EditCommand kEditCommands[] = {
135     // "delete-from-cursor" (chars, -2)
136     { "DeleteBackward", "" },
137     { "DeleteBackward", "" },
138     // "delete-from-cursor" (chars, 2)
139     { "DeleteForward", "" },
140     { "DeleteForward", "" },
141     // "delete-from-cursor" (word-ends, -1)
142     { "DeleteWordBackward", "" },
143     // "delete-from-cursor" (word-ends, 1)
144     { "DeleteWordForward", "" },
145     // "delete-from-cursor" (words, -1)
146     { "MoveWordBackward", "" },
147     { "DeleteWordForward", "" },
148     // "delete-from-cursor" (words, 1)
149     { "MoveWordForward", "" },
150     { "DeleteWordBackward", "" },
151     // "delete-from-cursor" (display-lines, -1)
152     { "MoveToBeginningOfLine", "" },
153     { "DeleteToEndOfLine", "" },
154     // "delete-from-cursor" (display-lines, 1)
155     { "MoveToBeginningOfLine", "" },
156     { "DeleteToEndOfLine", "" },
157     // "delete-from-cursor" (display-line-ends, -1)
158     { "DeleteToBeginningOfLine", "" },
159     // "delete-from-cursor" (display-line-ends, 1)
160     { "DeleteToEndOfLine", "" },
161     // "delete-from-cursor" (paragraph-ends, -1)
162     { "DeleteToBeginningOfParagraph", "" },
163     // "delete-from-cursor" (paragraph-ends, 1)
164     { "DeleteToEndOfParagraph", "" },
165     // "delete-from-cursor" (paragraphs, -1)
166     { "MoveToBeginningOfParagraph", "" },
167     { "DeleteToEndOfParagraph", "" },
168     // "delete-from-cursor" (paragraphs, 1)
169     { "MoveToBeginningOfParagraph", "" },
170     { "DeleteToEndOfParagraph", "" },
171   };
172 
173   TestKeyBinding(NewNativeWebKeyboardEvent(GDK_2, GDK_CONTROL_MASK),
174                  kEditCommands, arraysize(kEditCommands));
175 }
176 
TEST_F(GtkKeyBindingsHandlerTest,OtherActions)177 TEST_F(GtkKeyBindingsHandlerTest, OtherActions) {
178   static const EditCommand kBackspace[] = {
179     { "DeleteBackward", "" }
180   };
181   TestKeyBinding(NewNativeWebKeyboardEvent(GDK_3, GDK_CONTROL_MASK),
182                  kBackspace, arraysize(kBackspace));
183 
184   static const EditCommand kCopyClipboard[] = {
185     { "Copy", "" }
186   };
187   TestKeyBinding(NewNativeWebKeyboardEvent(GDK_4, GDK_CONTROL_MASK),
188                  kCopyClipboard, arraysize(kCopyClipboard));
189 
190   static const EditCommand kCutClipboard[] = {
191     { "Cut", "" }
192   };
193   TestKeyBinding(NewNativeWebKeyboardEvent(GDK_5, GDK_CONTROL_MASK),
194                  kCutClipboard, arraysize(kCutClipboard));
195 
196   static const EditCommand kInsertAtCursor[] = {
197     { "InsertText", "hello" }
198   };
199   TestKeyBinding(NewNativeWebKeyboardEvent(GDK_6, GDK_CONTROL_MASK),
200                  kInsertAtCursor, arraysize(kInsertAtCursor));
201 
202   static const EditCommand kPasteClipboard[] = {
203     { "Paste", "" }
204   };
205   TestKeyBinding(NewNativeWebKeyboardEvent(GDK_7, GDK_CONTROL_MASK),
206                  kPasteClipboard, arraysize(kPasteClipboard));
207 
208   static const EditCommand kSelectAll[] = {
209     { "Unselect", "" },
210     { "SelectAll", "" }
211   };
212   TestKeyBinding(NewNativeWebKeyboardEvent(GDK_8, GDK_CONTROL_MASK),
213                  kSelectAll, arraysize(kSelectAll));
214 
215   static const EditCommand kSetAnchor[] = {
216     { "SetMark", "" }
217   };
218   TestKeyBinding(NewNativeWebKeyboardEvent(GDK_9, GDK_CONTROL_MASK),
219                  kSetAnchor, arraysize(kSetAnchor));
220 }
221