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