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 21class GtkKeyBindingsHandlerTest : public testing::Test { 22 protected: 23 struct EditCommand { 24 const char* name; 25 const char* value; 26 }; 27 28 GtkKeyBindingsHandlerTest() 29 : window_(gtk_window_new(GTK_WINDOW_TOPLEVEL)), 30 handler_(NULL) { 31 FilePath gtkrc; 32 PathService::Get(chrome::DIR_TEST_DATA, >krc); 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 } 43 ~GtkKeyBindingsHandlerTest() { 44 gtk_widget_destroy(window_); 45 delete handler_; 46 } 47 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 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 91TEST_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 133TEST_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 177TEST_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