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