Home | History | Annotate | Download | only in renderer_host
      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