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 const base::NativeEvent& native_event); 67 blink::WebMouseWheelEvent MakeUntranslatedWebMouseWheelEventFromNativeEvent( 68 const base::NativeEvent& native_event); 69 blink::WebKeyboardEvent MakeWebKeyboardEventFromNativeEvent( 70 const base::NativeEvent& native_event); 71 blink::WebGestureEvent MakeWebGestureEventFromNativeEvent( 72 const 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 const 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 137 float offset_ordinal_x = 0.f; 138 float offset_ordinal_y = 0.f; 139 if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 && event->x_offset() == 0) { 140 webkit_event.deltaX = event->y_offset(); 141 webkit_event.deltaY = 0; 142 offset_ordinal_x = event->y_offset_ordinal(); 143 offset_ordinal_y = event->x_offset_ordinal(); 144 } else { 145 webkit_event.deltaX = event->x_offset(); 146 webkit_event.deltaY = event->y_offset(); 147 offset_ordinal_x = event->x_offset_ordinal(); 148 offset_ordinal_y = event->y_offset_ordinal(); 149 } 150 151 if (offset_ordinal_x != 0.f && webkit_event.deltaX != 0.f) 152 webkit_event.accelerationRatioX = offset_ordinal_x / webkit_event.deltaX; 153 webkit_event.wheelTicksX = webkit_event.deltaX / kPixelsPerTick; 154 webkit_event.wheelTicksY = webkit_event.deltaY / kPixelsPerTick; 155 if (offset_ordinal_y != 0.f && webkit_event.deltaY != 0.f) 156 webkit_event.accelerationRatioY = offset_ordinal_y / webkit_event.deltaY; 157 return webkit_event; 158 } 159 160 blink::WebGestureEvent MakeWebGestureEventFromAuraEvent( 161 ui::ScrollEvent* event) { 162 blink::WebGestureEvent webkit_event; 163 164 switch (event->type()) { 165 case ui::ET_SCROLL_FLING_START: 166 webkit_event.type = blink::WebInputEvent::GestureFlingStart; 167 webkit_event.data.flingStart.velocityX = event->x_offset(); 168 webkit_event.data.flingStart.velocityY = event->y_offset(); 169 break; 170 case ui::ET_SCROLL_FLING_CANCEL: 171 webkit_event.type = blink::WebInputEvent::GestureFlingCancel; 172 break; 173 case ui::ET_SCROLL: 174 NOTREACHED() << "Invalid gesture type: " << event->type(); 175 break; 176 default: 177 NOTREACHED() << "Unknown gesture type: " << event->type(); 178 } 179 180 webkit_event.sourceDevice = blink::WebGestureDeviceTouchpad; 181 webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags()); 182 webkit_event.timeStampSeconds = event->time_stamp().InSecondsF(); 183 return webkit_event; 184 } 185 186 #endif 187 188 blink::WebMouseEvent MakeWebMouseEventFromAuraEvent( 189 ui::MouseEvent* event); 190 blink::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent( 191 ui::MouseWheelEvent* event); 192 193 // General approach: 194 // 195 // ui::Event only carries a subset of possible event data provided to Aura by 196 // the host platform. WebKit utilizes a larger subset of that information than 197 // Aura itself. WebKit includes some built in cracking functionality that we 198 // rely on to obtain this information cleanly and consistently. 199 // 200 // The only place where an ui::Event's data differs from what the underlying 201 // base::NativeEvent would provide is position data, since we would like to 202 // provide coordinates relative to the aura::Window that is hosting the 203 // renderer, not the top level platform window. 204 // 205 // The approach is to fully construct a blink::WebInputEvent from the 206 // ui::Event's base::NativeEvent, and then replace the coordinate fields with 207 // the translated values from the ui::Event. 208 // 209 // The exception is mouse events on linux. The ui::MouseEvent contains enough 210 // necessary information to construct a WebMouseEvent. So instead of extracting 211 // the information from the XEvent, which can be tricky when supporting both 212 // XInput2 and XInput, the WebMouseEvent is constructed from the 213 // ui::MouseEvent. This will not be necessary once only XInput2 is supported. 214 // 215 216 blink::WebMouseEvent MakeWebMouseEvent(ui::MouseEvent* event) { 217 // Construct an untranslated event from the platform event data. 218 blink::WebMouseEvent webkit_event = 219 #if defined(OS_WIN) 220 // On Windows we have WM_ events comming from desktop and pure aura 221 // events comming from metro mode. 222 event->native_event().message ? 223 MakeUntranslatedWebMouseEventFromNativeEvent(event->native_event()) : 224 MakeWebMouseEventFromAuraEvent(event); 225 #else 226 MakeWebMouseEventFromAuraEvent(event); 227 #endif 228 // Replace the event's coordinate fields with translated position data from 229 // |event|. 230 webkit_event.windowX = webkit_event.x = event->x(); 231 webkit_event.windowY = webkit_event.y = event->y(); 232 233 #if defined(OS_WIN) 234 if (event->native_event().message) 235 return webkit_event; 236 #endif 237 const gfx::Point root_point = event->root_location(); 238 webkit_event.globalX = root_point.x(); 239 webkit_event.globalY = root_point.y(); 240 241 return webkit_event; 242 } 243 244 blink::WebMouseWheelEvent MakeWebMouseWheelEvent(ui::MouseWheelEvent* event) { 245 #if defined(OS_WIN) 246 // Construct an untranslated event from the platform event data. 247 blink::WebMouseWheelEvent webkit_event = event->native_event().message ? 248 MakeUntranslatedWebMouseWheelEventFromNativeEvent(event->native_event()) : 249 MakeWebMouseWheelEventFromAuraEvent(event); 250 #else 251 blink::WebMouseWheelEvent webkit_event = 252 MakeWebMouseWheelEventFromAuraEvent(event); 253 #endif 254 255 // Replace the event's coordinate fields with translated position data from 256 // |event|. 257 webkit_event.windowX = webkit_event.x = event->x(); 258 webkit_event.windowY = webkit_event.y = event->y(); 259 260 const gfx::Point root_point = event->root_location(); 261 webkit_event.globalX = root_point.x(); 262 webkit_event.globalY = root_point.y(); 263 264 return webkit_event; 265 } 266 267 blink::WebMouseWheelEvent MakeWebMouseWheelEvent(ui::ScrollEvent* event) { 268 #if defined(OS_WIN) 269 // Construct an untranslated event from the platform event data. 270 blink::WebMouseWheelEvent webkit_event = 271 MakeUntranslatedWebMouseWheelEventFromNativeEvent(event->native_event()); 272 #else 273 blink::WebMouseWheelEvent webkit_event = 274 MakeWebMouseWheelEventFromAuraEvent(event); 275 #endif 276 277 // Replace the event's coordinate fields with translated position data from 278 // |event|. 279 webkit_event.windowX = webkit_event.x = event->x(); 280 webkit_event.windowY = webkit_event.y = event->y(); 281 282 const gfx::Point root_point = event->root_location(); 283 webkit_event.globalX = root_point.x(); 284 webkit_event.globalY = root_point.y(); 285 286 return webkit_event; 287 } 288 289 blink::WebKeyboardEvent MakeWebKeyboardEvent(ui::KeyEvent* event) { 290 if (!event->HasNativeEvent()) 291 return blink::WebKeyboardEvent(); 292 293 // Windows can figure out whether or not to construct a RawKeyDown or a Char 294 // WebInputEvent based on the type of message carried in 295 // event->native_event(). X11 is not so fortunate, there is no separate 296 // translated event type, so DesktopHostLinux sends an extra KeyEvent with 297 // is_char() == true. We need to pass the ui::KeyEvent to the X11 function 298 // to detect this case so the right event type can be constructed. 299 #if defined(OS_WIN) 300 // Key events require no translation by the aura system. 301 return MakeWebKeyboardEventFromNativeEvent(event->native_event()); 302 #else 303 return MakeWebKeyboardEventFromAuraEvent(event); 304 #endif 305 } 306 307 blink::WebGestureEvent MakeWebGestureEvent(ui::GestureEvent* event) { 308 blink::WebGestureEvent gesture_event; 309 #if defined(OS_WIN) 310 if (event->HasNativeEvent()) 311 gesture_event = MakeWebGestureEventFromNativeEvent(event->native_event()); 312 else 313 gesture_event = MakeWebGestureEventFromUIEvent(*event); 314 #else 315 gesture_event = MakeWebGestureEventFromUIEvent(*event); 316 #endif 317 318 gesture_event.x = event->x(); 319 gesture_event.y = event->y(); 320 321 const gfx::Point root_point = event->root_location(); 322 gesture_event.globalX = root_point.x(); 323 gesture_event.globalY = root_point.y(); 324 325 return gesture_event; 326 } 327 328 blink::WebGestureEvent MakeWebGestureEvent(ui::ScrollEvent* event) { 329 blink::WebGestureEvent gesture_event; 330 331 #if defined(OS_WIN) 332 gesture_event = MakeWebGestureEventFromNativeEvent(event->native_event()); 333 #else 334 gesture_event = MakeWebGestureEventFromAuraEvent(event); 335 #endif 336 337 gesture_event.x = event->x(); 338 gesture_event.y = event->y(); 339 340 const gfx::Point root_point = event->root_location(); 341 gesture_event.globalX = root_point.x(); 342 gesture_event.globalY = root_point.y(); 343 344 return gesture_event; 345 } 346 347 blink::WebGestureEvent MakeWebGestureEventFlingCancel() { 348 blink::WebGestureEvent gesture_event; 349 350 // All other fields are ignored on a GestureFlingCancel event. 351 gesture_event.type = blink::WebInputEvent::GestureFlingCancel; 352 gesture_event.sourceDevice = blink::WebGestureDeviceTouchpad; 353 return gesture_event; 354 } 355 356 blink::WebMouseEvent MakeWebMouseEventFromAuraEvent(ui::MouseEvent* event) { 357 blink::WebMouseEvent webkit_event; 358 359 webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags()); 360 webkit_event.timeStampSeconds = event->time_stamp().InSecondsF(); 361 362 webkit_event.button = blink::WebMouseEvent::ButtonNone; 363 if (event->flags() & ui::EF_LEFT_MOUSE_BUTTON) 364 webkit_event.button = blink::WebMouseEvent::ButtonLeft; 365 if (event->flags() & ui::EF_MIDDLE_MOUSE_BUTTON) 366 webkit_event.button = blink::WebMouseEvent::ButtonMiddle; 367 if (event->flags() & ui::EF_RIGHT_MOUSE_BUTTON) 368 webkit_event.button = blink::WebMouseEvent::ButtonRight; 369 370 switch (event->type()) { 371 case ui::ET_MOUSE_PRESSED: 372 webkit_event.type = blink::WebInputEvent::MouseDown; 373 webkit_event.clickCount = event->GetClickCount(); 374 break; 375 case ui::ET_MOUSE_RELEASED: 376 webkit_event.type = blink::WebInputEvent::MouseUp; 377 webkit_event.clickCount = event->GetClickCount(); 378 break; 379 case ui::ET_MOUSE_ENTERED: 380 case ui::ET_MOUSE_EXITED: 381 case ui::ET_MOUSE_MOVED: 382 case ui::ET_MOUSE_DRAGGED: 383 webkit_event.type = blink::WebInputEvent::MouseMove; 384 break; 385 default: 386 NOTIMPLEMENTED() << "Received unexpected event: " << event->type(); 387 break; 388 } 389 390 return webkit_event; 391 } 392 393 blink::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent( 394 ui::MouseWheelEvent* event) { 395 blink::WebMouseWheelEvent webkit_event; 396 397 webkit_event.type = blink::WebInputEvent::MouseWheel; 398 webkit_event.button = blink::WebMouseEvent::ButtonNone; 399 webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags()); 400 webkit_event.timeStampSeconds = event->time_stamp().InSecondsF(); 401 402 if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 && event->x_offset() == 0) { 403 webkit_event.deltaX = event->y_offset(); 404 webkit_event.deltaY = 0; 405 } else { 406 webkit_event.deltaX = event->x_offset(); 407 webkit_event.deltaY = event->y_offset(); 408 } 409 410 webkit_event.wheelTicksX = webkit_event.deltaX / kPixelsPerTick; 411 webkit_event.wheelTicksY = webkit_event.deltaY / kPixelsPerTick; 412 413 return webkit_event; 414 } 415 416 } // namespace content 417