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     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