1 /* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 33 #include <gdk/gdk.h> 34 #include <gdk/gdkkeysyms.h> 35 #include <gtest/gtest.h> 36 37 #include "WebInputEvent.h" 38 #include "WebInputEventConversion.h" 39 #include "WebInputEventFactory.h" 40 #include "core/events/KeyboardEvent.h" 41 42 using blink::WebInputEvent; 43 using blink::WebKeyboardEvent; 44 using blink::WebMouseEvent; 45 using blink::WebInputEventFactory; 46 47 namespace { 48 49 TEST(WebInputEventFactoryTest, DoubleClick) 50 { 51 GdkEventButton firstClick; 52 firstClick.type = GDK_BUTTON_PRESS; 53 firstClick.window = static_cast<GdkWindow*>(GINT_TO_POINTER(1)); 54 firstClick.x = firstClick.y = firstClick.x_root = firstClick.y_root = 100; 55 firstClick.state = 0; 56 firstClick.time = 0; 57 firstClick.button = 1; 58 59 // Single click works. 60 WebMouseEvent firstClickEvent = WebInputEventFactory::mouseEvent(&firstClick); 61 EXPECT_EQ(1, firstClickEvent.clickCount); 62 63 // Make sure double click works. 64 GdkEventButton secondClick = firstClick; 65 secondClick.time = firstClick.time + 100; 66 WebMouseEvent secondClickEvent = WebInputEventFactory::mouseEvent(&secondClick); 67 EXPECT_EQ(2, secondClickEvent.clickCount); 68 69 // Reset the click count. 70 firstClick.time += 10000; 71 firstClickEvent = WebInputEventFactory::mouseEvent(&firstClick); 72 EXPECT_EQ(1, firstClickEvent.clickCount); 73 74 // Two clicks with a long gap in between aren't counted as a double click. 75 secondClick = firstClick; 76 secondClick.time = firstClick.time + 1000; 77 secondClickEvent = WebInputEventFactory::mouseEvent(&secondClick); 78 EXPECT_EQ(1, secondClickEvent.clickCount); 79 80 // Reset the click count. 81 firstClick.time += 10000; 82 firstClickEvent = WebInputEventFactory::mouseEvent(&firstClick); 83 EXPECT_EQ(1, firstClickEvent.clickCount); 84 85 // Two clicks far apart (horizontally) aren't counted as a double click. 86 secondClick = firstClick; 87 secondClick.time = firstClick.time + 1; 88 secondClick.x = firstClick.x + 100; 89 secondClickEvent = WebInputEventFactory::mouseEvent(&secondClick); 90 EXPECT_EQ(1, secondClickEvent.clickCount); 91 92 // Reset the click count. 93 firstClick.time += 10000; 94 firstClickEvent = WebInputEventFactory::mouseEvent(&firstClick); 95 EXPECT_EQ(1, firstClickEvent.clickCount); 96 97 // Two clicks far apart (vertically) aren't counted as a double click. 98 secondClick = firstClick; 99 secondClick.time = firstClick.time + 1; 100 secondClick.x = firstClick.y + 100; 101 secondClickEvent = WebInputEventFactory::mouseEvent(&secondClick); 102 EXPECT_EQ(1, secondClickEvent.clickCount); 103 104 // Reset the click count. 105 firstClick.time += 10000; 106 firstClickEvent = WebInputEventFactory::mouseEvent(&firstClick); 107 EXPECT_EQ(1, firstClickEvent.clickCount); 108 109 // Two clicks on different windows aren't a double click. 110 secondClick = firstClick; 111 secondClick.time = firstClick.time + 1; 112 secondClick.window = static_cast<GdkWindow*>(GINT_TO_POINTER(2)); 113 secondClickEvent = WebInputEventFactory::mouseEvent(&secondClick); 114 EXPECT_EQ(1, secondClickEvent.clickCount); 115 } 116 117 TEST(WebInputEventFactoryTest, MouseUpClickCount) 118 { 119 GdkEventButton mouseDown; 120 memset(&mouseDown, 0, sizeof(mouseDown)); 121 mouseDown.type = GDK_BUTTON_PRESS; 122 mouseDown.window = static_cast<GdkWindow*>(GINT_TO_POINTER(1)); 123 mouseDown.x = mouseDown.y = mouseDown.x_root = mouseDown.y_root = 100; 124 mouseDown.time = 0; 125 mouseDown.button = 1; 126 127 // Properly set the last click time, so that the internal state won't be affected by previous tests. 128 WebInputEventFactory::mouseEvent(&mouseDown); 129 130 mouseDown.time += 10000; 131 GdkEventButton mouseUp = mouseDown; 132 mouseUp.type = GDK_BUTTON_RELEASE; 133 WebMouseEvent mouseDownEvent; 134 WebMouseEvent mouseUpEvent; 135 136 // Click for three times. 137 for (int i = 1; i < 4; ++i) { 138 mouseDown.time += 100; 139 mouseDownEvent = WebInputEventFactory::mouseEvent(&mouseDown); 140 EXPECT_EQ(i, mouseDownEvent.clickCount); 141 142 mouseUp.time = mouseDown.time + 50; 143 mouseUpEvent = WebInputEventFactory::mouseEvent(&mouseUp); 144 EXPECT_EQ(i, mouseUpEvent.clickCount); 145 } 146 147 // Reset the click count. 148 mouseDown.time += 10000; 149 mouseDownEvent = WebInputEventFactory::mouseEvent(&mouseDown); 150 EXPECT_EQ(1, mouseDownEvent.clickCount); 151 152 // Moving the cursor for a significant distance will reset the click count to 0. 153 GdkEventMotion mouseMove; 154 memset(&mouseMove, 0, sizeof(mouseMove)); 155 mouseMove.type = GDK_MOTION_NOTIFY; 156 mouseMove.window = mouseDown.window; 157 mouseMove.time = mouseDown.time; 158 mouseMove.x = mouseMove.y = mouseMove.x_root = mouseMove.y_root = mouseDown.x + 100; 159 WebInputEventFactory::mouseEvent(&mouseMove); 160 161 mouseUp.time = mouseDown.time + 50; 162 mouseUpEvent = WebInputEventFactory::mouseEvent(&mouseUp); 163 EXPECT_EQ(0, mouseUpEvent.clickCount); 164 165 // Reset the click count. 166 mouseDown.time += 10000; 167 mouseDownEvent = WebInputEventFactory::mouseEvent(&mouseDown); 168 EXPECT_EQ(1, mouseDownEvent.clickCount); 169 170 // Moving the cursor with a significant delay will reset the click count to 0. 171 mouseMove.time = mouseDown.time + 1000; 172 mouseMove.x = mouseMove.y = mouseMove.x_root = mouseMove.y_root = mouseDown.x; 173 WebInputEventFactory::mouseEvent(&mouseMove); 174 175 mouseUp.time = mouseMove.time + 50; 176 mouseUpEvent = WebInputEventFactory::mouseEvent(&mouseUp); 177 EXPECT_EQ(0, mouseUpEvent.clickCount); 178 } 179 180 TEST(WebInputEventFactoryTest, NumPadConversion) 181 { 182 // Construct a GDK input event for the numpad "5" key. 183 char five[] = "5"; 184 GdkEventKey gdkEvent; 185 memset(&gdkEvent, 0, sizeof(GdkEventKey)); 186 gdkEvent.type = GDK_KEY_PRESS; 187 gdkEvent.keyval = GDK_KP_5; 188 gdkEvent.string = five; 189 190 // Numpad flag should be set on the WebKeyboardEvent. 191 WebKeyboardEvent webEvent = WebInputEventFactory::keyboardEvent(&gdkEvent); 192 EXPECT_TRUE(webEvent.modifiers & WebInputEvent::IsKeyPad); 193 194 // Round-trip through the WebCore KeyboardEvent class. 195 blink::PlatformKeyboardEventBuilder platformBuilder(webEvent); 196 RefPtr<WebCore::KeyboardEvent> keypress = WebCore::KeyboardEvent::create(platformBuilder, 0); 197 EXPECT_TRUE(keypress->location() == WebCore::KeyboardEvent::DOM_KEY_LOCATION_NUMPAD); 198 199 blink::WebKeyboardEventBuilder builder(*keypress); 200 EXPECT_TRUE(builder.modifiers & WebInputEvent::IsKeyPad); 201 } 202 203 } // anonymous namespace 204