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/web_input_event_aura.h" 6 7 #include "content/browser/renderer_host/input/web_input_event_util.h" 8 #include "content/browser/renderer_host/ui_events_helper.h" 9 #include "ui/aura/window.h" 10 #include "ui/events/event.h" 11 #include "ui/events/event_utils.h" 12 13 #if defined(USE_X11) || defined(USE_OZONE) 14 #include "ui/events/keycodes/dom4/keycode_converter.h" 15 #endif 16 17 namespace content { 18 19 #if defined(OS_WIN) 20 blink::WebMouseEvent MakeUntranslatedWebMouseEventFromNativeEvent( 21 const base::NativeEvent& native_event); 22 blink::WebMouseWheelEvent MakeUntranslatedWebMouseWheelEventFromNativeEvent( 23 const base::NativeEvent& native_event); 24 blink::WebKeyboardEvent MakeWebKeyboardEventFromNativeEvent( 25 const base::NativeEvent& native_event); 26 blink::WebGestureEvent MakeWebGestureEventFromNativeEvent( 27 const base::NativeEvent& native_event); 28 #endif 29 #if defined(USE_X11) || defined(USE_OZONE) 30 blink::WebKeyboardEvent MakeWebKeyboardEventFromAuraEvent( 31 ui::KeyEvent* event) { 32 blink::WebKeyboardEvent webkit_event; 33 34 webkit_event.timeStampSeconds = event->time_stamp().InSecondsF(); 35 webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags()); 36 37 switch (event->type()) { 38 case ui::ET_KEY_PRESSED: 39 webkit_event.type = event->is_char() ? blink::WebInputEvent::Char : 40 blink::WebInputEvent::RawKeyDown; 41 break; 42 case ui::ET_KEY_RELEASED: 43 webkit_event.type = blink::WebInputEvent::KeyUp; 44 break; 45 default: 46 NOTREACHED(); 47 } 48 49 if (webkit_event.modifiers & blink::WebInputEvent::AltKey) 50 webkit_event.isSystemKey = true; 51 52 webkit_event.windowsKeyCode = event->GetLocatedWindowsKeyboardCode(); 53 webkit_event.nativeKeyCode = 54 ui::KeycodeConverter::CodeToNativeKeycode(event->code().c_str()); 55 webkit_event.unmodifiedText[0] = event->GetUnmodifiedText(); 56 webkit_event.text[0] = event->GetText(); 57 58 webkit_event.setKeyIdentifierFromWindowsKeyCode(); 59 60 return webkit_event; 61 } 62 63 blink::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent( 64 ui::ScrollEvent* event) { 65 blink::WebMouseWheelEvent webkit_event; 66 67 webkit_event.type = blink::WebInputEvent::MouseWheel; 68 webkit_event.button = blink::WebMouseEvent::ButtonNone; 69 webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags()); 70 webkit_event.timeStampSeconds = event->time_stamp().InSecondsF(); 71 webkit_event.hasPreciseScrollingDeltas = true; 72 73 float offset_ordinal_x = 0.f; 74 float offset_ordinal_y = 0.f; 75 if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 && event->x_offset() == 0) { 76 webkit_event.deltaX = event->y_offset(); 77 webkit_event.deltaY = 0; 78 offset_ordinal_x = event->y_offset_ordinal(); 79 offset_ordinal_y = event->x_offset_ordinal(); 80 } else { 81 webkit_event.deltaX = event->x_offset(); 82 webkit_event.deltaY = event->y_offset(); 83 offset_ordinal_x = event->x_offset_ordinal(); 84 offset_ordinal_y = event->y_offset_ordinal(); 85 } 86 87 if (offset_ordinal_x != 0.f && webkit_event.deltaX != 0.f) 88 webkit_event.accelerationRatioX = offset_ordinal_x / webkit_event.deltaX; 89 webkit_event.wheelTicksX = webkit_event.deltaX / kPixelsPerTick; 90 webkit_event.wheelTicksY = webkit_event.deltaY / kPixelsPerTick; 91 if (offset_ordinal_y != 0.f && webkit_event.deltaY != 0.f) 92 webkit_event.accelerationRatioY = offset_ordinal_y / webkit_event.deltaY; 93 return webkit_event; 94 } 95 96 blink::WebGestureEvent MakeWebGestureEventFromAuraEvent( 97 ui::ScrollEvent* event) { 98 blink::WebGestureEvent webkit_event; 99 100 switch (event->type()) { 101 case ui::ET_SCROLL_FLING_START: 102 webkit_event.type = blink::WebInputEvent::GestureFlingStart; 103 webkit_event.data.flingStart.velocityX = event->x_offset(); 104 webkit_event.data.flingStart.velocityY = event->y_offset(); 105 break; 106 case ui::ET_SCROLL_FLING_CANCEL: 107 webkit_event.type = blink::WebInputEvent::GestureFlingCancel; 108 break; 109 case ui::ET_SCROLL: 110 NOTREACHED() << "Invalid gesture type: " << event->type(); 111 break; 112 default: 113 NOTREACHED() << "Unknown gesture type: " << event->type(); 114 } 115 116 webkit_event.sourceDevice = blink::WebGestureDeviceTouchpad; 117 webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags()); 118 webkit_event.timeStampSeconds = event->time_stamp().InSecondsF(); 119 return webkit_event; 120 } 121 122 #endif 123 124 blink::WebMouseEvent MakeWebMouseEventFromAuraEvent( 125 ui::MouseEvent* event); 126 blink::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent( 127 ui::MouseWheelEvent* event); 128 129 // General approach: 130 // 131 // ui::Event only carries a subset of possible event data provided to Aura by 132 // the host platform. WebKit utilizes a larger subset of that information than 133 // Aura itself. WebKit includes some built in cracking functionality that we 134 // rely on to obtain this information cleanly and consistently. 135 // 136 // The only place where an ui::Event's data differs from what the underlying 137 // base::NativeEvent would provide is position data, since we would like to 138 // provide coordinates relative to the aura::Window that is hosting the 139 // renderer, not the top level platform window. 140 // 141 // The approach is to fully construct a blink::WebInputEvent from the 142 // ui::Event's base::NativeEvent, and then replace the coordinate fields with 143 // the translated values from the ui::Event. 144 // 145 // The exception is mouse events on linux. The ui::MouseEvent contains enough 146 // necessary information to construct a WebMouseEvent. So instead of extracting 147 // the information from the XEvent, which can be tricky when supporting both 148 // XInput2 and XInput, the WebMouseEvent is constructed from the 149 // ui::MouseEvent. This will not be necessary once only XInput2 is supported. 150 // 151 152 blink::WebMouseEvent MakeWebMouseEvent(ui::MouseEvent* event) { 153 // Construct an untranslated event from the platform event data. 154 blink::WebMouseEvent webkit_event = 155 #if defined(OS_WIN) 156 // On Windows we have WM_ events comming from desktop and pure aura 157 // events comming from metro mode. 158 event->native_event().message ? 159 MakeUntranslatedWebMouseEventFromNativeEvent(event->native_event()) : 160 MakeWebMouseEventFromAuraEvent(event); 161 #else 162 MakeWebMouseEventFromAuraEvent(event); 163 #endif 164 // Replace the event's coordinate fields with translated position data from 165 // |event|. 166 webkit_event.windowX = webkit_event.x = event->x(); 167 webkit_event.windowY = webkit_event.y = event->y(); 168 169 #if defined(OS_WIN) 170 if (event->native_event().message) 171 return webkit_event; 172 #endif 173 const gfx::Point root_point = event->root_location(); 174 webkit_event.globalX = root_point.x(); 175 webkit_event.globalY = root_point.y(); 176 177 return webkit_event; 178 } 179 180 blink::WebMouseWheelEvent MakeWebMouseWheelEvent(ui::MouseWheelEvent* event) { 181 #if defined(OS_WIN) 182 // Construct an untranslated event from the platform event data. 183 blink::WebMouseWheelEvent webkit_event = event->native_event().message ? 184 MakeUntranslatedWebMouseWheelEventFromNativeEvent(event->native_event()) : 185 MakeWebMouseWheelEventFromAuraEvent(event); 186 #else 187 blink::WebMouseWheelEvent webkit_event = 188 MakeWebMouseWheelEventFromAuraEvent(event); 189 #endif 190 191 // Replace the event's coordinate fields with translated position data from 192 // |event|. 193 webkit_event.windowX = webkit_event.x = event->x(); 194 webkit_event.windowY = webkit_event.y = event->y(); 195 196 const gfx::Point root_point = event->root_location(); 197 webkit_event.globalX = root_point.x(); 198 webkit_event.globalY = root_point.y(); 199 200 return webkit_event; 201 } 202 203 blink::WebMouseWheelEvent MakeWebMouseWheelEvent(ui::ScrollEvent* event) { 204 #if defined(OS_WIN) 205 // Construct an untranslated event from the platform event data. 206 blink::WebMouseWheelEvent webkit_event = 207 MakeUntranslatedWebMouseWheelEventFromNativeEvent(event->native_event()); 208 #else 209 blink::WebMouseWheelEvent webkit_event = 210 MakeWebMouseWheelEventFromAuraEvent(event); 211 #endif 212 213 // Replace the event's coordinate fields with translated position data from 214 // |event|. 215 webkit_event.windowX = webkit_event.x = event->x(); 216 webkit_event.windowY = webkit_event.y = event->y(); 217 218 const gfx::Point root_point = event->root_location(); 219 webkit_event.globalX = root_point.x(); 220 webkit_event.globalY = root_point.y(); 221 222 return webkit_event; 223 } 224 225 blink::WebKeyboardEvent MakeWebKeyboardEvent(ui::KeyEvent* event) { 226 // Windows can figure out whether or not to construct a RawKeyDown or a Char 227 // WebInputEvent based on the type of message carried in 228 // event->native_event(). X11 is not so fortunate, there is no separate 229 // translated event type, so DesktopHostLinux sends an extra KeyEvent with 230 // is_char() == true. We need to pass the ui::KeyEvent to the X11 function 231 // to detect this case so the right event type can be constructed. 232 #if defined(OS_WIN) 233 if (!event->HasNativeEvent()) 234 return blink::WebKeyboardEvent(); 235 236 // Key events require no translation by the aura system. 237 return MakeWebKeyboardEventFromNativeEvent(event->native_event()); 238 #else 239 return MakeWebKeyboardEventFromAuraEvent(event); 240 #endif 241 } 242 243 blink::WebGestureEvent MakeWebGestureEvent(ui::GestureEvent* event) { 244 blink::WebGestureEvent gesture_event; 245 #if defined(OS_WIN) 246 if (event->HasNativeEvent()) 247 gesture_event = MakeWebGestureEventFromNativeEvent(event->native_event()); 248 else 249 gesture_event = MakeWebGestureEventFromUIEvent(*event); 250 #else 251 gesture_event = MakeWebGestureEventFromUIEvent(*event); 252 #endif 253 254 gesture_event.x = event->x(); 255 gesture_event.y = event->y(); 256 257 const gfx::Point root_point = event->root_location(); 258 gesture_event.globalX = root_point.x(); 259 gesture_event.globalY = root_point.y(); 260 261 return gesture_event; 262 } 263 264 blink::WebGestureEvent MakeWebGestureEvent(ui::ScrollEvent* event) { 265 blink::WebGestureEvent gesture_event; 266 267 #if defined(OS_WIN) 268 gesture_event = MakeWebGestureEventFromNativeEvent(event->native_event()); 269 #else 270 gesture_event = MakeWebGestureEventFromAuraEvent(event); 271 #endif 272 273 gesture_event.x = event->x(); 274 gesture_event.y = event->y(); 275 276 const gfx::Point root_point = event->root_location(); 277 gesture_event.globalX = root_point.x(); 278 gesture_event.globalY = root_point.y(); 279 280 return gesture_event; 281 } 282 283 blink::WebGestureEvent MakeWebGestureEventFlingCancel() { 284 blink::WebGestureEvent gesture_event; 285 286 // All other fields are ignored on a GestureFlingCancel event. 287 gesture_event.type = blink::WebInputEvent::GestureFlingCancel; 288 gesture_event.sourceDevice = blink::WebGestureDeviceTouchpad; 289 return gesture_event; 290 } 291 292 blink::WebMouseEvent MakeWebMouseEventFromAuraEvent(ui::MouseEvent* event) { 293 blink::WebMouseEvent webkit_event; 294 295 webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags()); 296 webkit_event.timeStampSeconds = event->time_stamp().InSecondsF(); 297 298 webkit_event.button = blink::WebMouseEvent::ButtonNone; 299 int button_flags = event->flags(); 300 if (event->type() == ui::ET_MOUSE_PRESSED || 301 event->type() == ui::ET_MOUSE_RELEASED) { 302 // We want to use changed_button_flags() for mouse pressed & released. 303 // These flags can be used only if they are set which is not always the case 304 // (see e.g. GetChangedMouseButtonFlagsFromNative() in events_win.cc). 305 if (event->changed_button_flags()) 306 button_flags = event->changed_button_flags(); 307 } 308 if (button_flags & ui::EF_LEFT_MOUSE_BUTTON) 309 webkit_event.button = blink::WebMouseEvent::ButtonLeft; 310 if (button_flags & ui::EF_MIDDLE_MOUSE_BUTTON) 311 webkit_event.button = blink::WebMouseEvent::ButtonMiddle; 312 if (button_flags & ui::EF_RIGHT_MOUSE_BUTTON) 313 webkit_event.button = blink::WebMouseEvent::ButtonRight; 314 315 switch (event->type()) { 316 case ui::ET_MOUSE_PRESSED: 317 webkit_event.type = blink::WebInputEvent::MouseDown; 318 webkit_event.clickCount = event->GetClickCount(); 319 break; 320 case ui::ET_MOUSE_RELEASED: 321 webkit_event.type = blink::WebInputEvent::MouseUp; 322 webkit_event.clickCount = event->GetClickCount(); 323 break; 324 case ui::ET_MOUSE_ENTERED: 325 case ui::ET_MOUSE_EXITED: 326 case ui::ET_MOUSE_MOVED: 327 case ui::ET_MOUSE_DRAGGED: 328 webkit_event.type = blink::WebInputEvent::MouseMove; 329 break; 330 default: 331 NOTIMPLEMENTED() << "Received unexpected event: " << event->type(); 332 break; 333 } 334 335 return webkit_event; 336 } 337 338 blink::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent( 339 ui::MouseWheelEvent* event) { 340 blink::WebMouseWheelEvent webkit_event; 341 342 webkit_event.type = blink::WebInputEvent::MouseWheel; 343 webkit_event.button = blink::WebMouseEvent::ButtonNone; 344 webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags()); 345 webkit_event.timeStampSeconds = event->time_stamp().InSecondsF(); 346 347 if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 && event->x_offset() == 0) { 348 webkit_event.deltaX = event->y_offset(); 349 webkit_event.deltaY = 0; 350 } else { 351 webkit_event.deltaX = event->x_offset(); 352 webkit_event.deltaY = event->y_offset(); 353 } 354 355 webkit_event.wheelTicksX = webkit_event.deltaX / kPixelsPerTick; 356 webkit_event.wheelTicksY = webkit_event.deltaY / kPixelsPerTick; 357 358 return webkit_event; 359 } 360 361 } // namespace content 362