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 // Portions based heavily on:
      6 // third_party/WebKit/public/web/gtk/WebInputEventFactory.cpp
      7 //
      8 /*
      9  * Copyright (C) 2006-2011 Google Inc. All rights reserved.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions are
     13  * met:
     14  *
     15  *     * Redistributions of source code must retain the above copyright
     16  * notice, this list of conditions and the following disclaimer.
     17  *     * Redistributions in binary form must reproduce the above
     18  * copyright notice, this list of conditions and the following disclaimer
     19  * in the documentation and/or other materials provided with the
     20  * distribution.
     21  *     * Neither the name of Google Inc. nor the names of its
     22  * contributors may be used to endorse or promote products derived from
     23  * this software without specific prior written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     29  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     31  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     35  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     36  */
     37 
     38 #include "content/browser/renderer_host/web_input_event_aura.h"
     39 
     40 #include <X11/keysym.h>
     41 #include <X11/Xlib.h>
     42 #include <X11/Xutil.h>
     43 #include <cstdlib>
     44 
     45 #include "base/event_types.h"
     46 #include "base/logging.h"
     47 #include "content/browser/renderer_host/ui_events_helper.h"
     48 #include "ui/base/events/event.h"
     49 #include "ui/base/events/event_constants.h"
     50 #include "ui/base/keycodes/keyboard_code_conversion_x.h"
     51 #include "ui/base/keycodes/keyboard_codes.h"
     52 
     53 namespace content {
     54 
     55 // chromium WebKit does not provide a WebInputEventFactory for X11, so we have
     56 // to do the work here ourselves.
     57 
     58 namespace {
     59 
     60 int XKeyEventToWindowsKeyCode(XKeyEvent* event) {
     61   int windows_key_code =
     62       ui::KeyboardCodeFromXKeyEvent(reinterpret_cast<XEvent*>(event));
     63   if (windows_key_code == ui::VKEY_SHIFT ||
     64       windows_key_code == ui::VKEY_CONTROL ||
     65       windows_key_code == ui::VKEY_MENU) {
     66     // To support DOM3 'location' attribute, we need to lookup an X KeySym and
     67     // set ui::VKEY_[LR]XXX instead of ui::VKEY_XXX.
     68     KeySym keysym = XK_VoidSymbol;
     69     XLookupString(event, NULL, 0, &keysym, NULL);
     70     switch (keysym) {
     71       case XK_Shift_L:
     72         return ui::VKEY_LSHIFT;
     73       case XK_Shift_R:
     74         return ui::VKEY_RSHIFT;
     75       case XK_Control_L:
     76         return ui::VKEY_LCONTROL;
     77       case XK_Control_R:
     78         return ui::VKEY_RCONTROL;
     79       case XK_Meta_L:
     80       case XK_Alt_L:
     81         return ui::VKEY_LMENU;
     82       case XK_Meta_R:
     83       case XK_Alt_R:
     84         return ui::VKEY_RMENU;
     85     }
     86   }
     87   return windows_key_code;
     88 }
     89 
     90 // From third_party/WebKit/Source/web/gtk/WebInputEventFactory.cpp:
     91 WebKit::WebUChar GetControlCharacter(int windows_key_code, bool shift) {
     92   if (windows_key_code >= ui::VKEY_A &&
     93     windows_key_code <= ui::VKEY_Z) {
     94     // ctrl-A ~ ctrl-Z map to \x01 ~ \x1A
     95     return windows_key_code - ui::VKEY_A + 1;
     96   }
     97   if (shift) {
     98     // following graphics chars require shift key to input.
     99     switch (windows_key_code) {
    100       // ctrl-@ maps to \x00 (Null byte)
    101       case ui::VKEY_2:
    102         return 0;
    103       // ctrl-^ maps to \x1E (Record separator, Information separator two)
    104       case ui::VKEY_6:
    105         return 0x1E;
    106       // ctrl-_ maps to \x1F (Unit separator, Information separator one)
    107       case ui::VKEY_OEM_MINUS:
    108         return 0x1F;
    109       // Returns 0 for all other keys to avoid inputting unexpected chars.
    110       default:
    111         break;
    112     }
    113   } else {
    114     switch (windows_key_code) {
    115       // ctrl-[ maps to \x1B (Escape)
    116       case ui::VKEY_OEM_4:
    117         return 0x1B;
    118       // ctrl-\ maps to \x1C (File separator, Information separator four)
    119       case ui::VKEY_OEM_5:
    120         return 0x1C;
    121       // ctrl-] maps to \x1D (Group separator, Information separator three)
    122       case ui::VKEY_OEM_6:
    123         return 0x1D;
    124       // ctrl-Enter maps to \x0A (Line feed)
    125       case ui::VKEY_RETURN:
    126         return 0x0A;
    127       // Returns 0 for all other keys to avoid inputting unexpected chars.
    128       default:
    129         break;
    130     }
    131   }
    132   return 0;
    133 }
    134 
    135 }  // namespace
    136 
    137 WebKit::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent(
    138     ui::ScrollEvent* event) {
    139   WebKit::WebMouseWheelEvent webkit_event;
    140 
    141   webkit_event.type = WebKit::WebInputEvent::MouseWheel;
    142   webkit_event.button = WebKit::WebMouseEvent::ButtonNone;
    143   webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
    144   webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
    145   webkit_event.hasPreciseScrollingDeltas = true;
    146   webkit_event.deltaX = event->x_offset();
    147   if (event->x_offset_ordinal() != 0.f && event->x_offset() != 0.f) {
    148     webkit_event.accelerationRatioX =
    149         event->x_offset_ordinal() / event->x_offset();
    150   }
    151   webkit_event.wheelTicksX = webkit_event.deltaX / kPixelsPerTick;
    152   webkit_event.deltaY = event->y_offset();
    153   webkit_event.wheelTicksY = webkit_event.deltaY / kPixelsPerTick;
    154   if (event->y_offset_ordinal() != 0.f && event->y_offset() != 0.f) {
    155     webkit_event.accelerationRatioY =
    156         event->y_offset_ordinal() / event->y_offset();
    157   }
    158 
    159   return webkit_event;
    160 }
    161 
    162 // NOTE: ui::ScrollEvent instances come from the touchpad.
    163 WebKit::WebGestureEvent MakeWebGestureEventFromAuraEvent(
    164     ui::ScrollEvent* event) {
    165   WebKit::WebGestureEvent webkit_event;
    166 
    167   switch (event->type()) {
    168     case ui::ET_SCROLL_FLING_START:
    169       webkit_event.type = WebKit::WebInputEvent::GestureFlingStart;
    170       webkit_event.data.flingStart.velocityX = event->x_offset();
    171       webkit_event.data.flingStart.velocityY = event->y_offset();
    172       break;
    173     case ui::ET_SCROLL_FLING_CANCEL:
    174       webkit_event.type = WebKit::WebInputEvent::GestureFlingCancel;
    175       break;
    176     case ui::ET_SCROLL:
    177       NOTREACHED() << "Invalid gesture type: " << event->type();
    178       break;
    179     default:
    180       NOTREACHED() << "Unknown gesture type: " << event->type();
    181   }
    182 
    183   webkit_event.sourceDevice = WebKit::WebGestureEvent::Touchpad;
    184   webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
    185   webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
    186 
    187   return webkit_event;
    188 }
    189 
    190 WebKit::WebKeyboardEvent MakeWebKeyboardEventFromAuraEvent(
    191     ui::KeyEvent* event) {
    192   base::NativeEvent native_event = event->native_event();
    193   WebKit::WebKeyboardEvent webkit_event;
    194   XKeyEvent* native_key_event = &native_event->xkey;
    195 
    196   webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
    197   webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
    198 
    199   switch (native_event->type) {
    200     case KeyPress:
    201       webkit_event.type = event->is_char() ? WebKit::WebInputEvent::Char :
    202           WebKit::WebInputEvent::RawKeyDown;
    203       break;
    204     case KeyRelease:
    205       webkit_event.type = WebKit::WebInputEvent::KeyUp;
    206       break;
    207     default:
    208       NOTREACHED();
    209   }
    210 
    211   if (webkit_event.modifiers & WebKit::WebInputEvent::AltKey)
    212     webkit_event.isSystemKey = true;
    213 
    214   webkit_event.windowsKeyCode = XKeyEventToWindowsKeyCode(native_key_event);
    215   webkit_event.nativeKeyCode = native_key_event->keycode;
    216 
    217   if (webkit_event.windowsKeyCode == ui::VKEY_RETURN)
    218     webkit_event.unmodifiedText[0] = '\r';
    219   else
    220     webkit_event.unmodifiedText[0] = ui::GetCharacterFromXEvent(native_event);
    221 
    222   if (webkit_event.modifiers & WebKit::WebInputEvent::ControlKey) {
    223     webkit_event.text[0] =
    224         GetControlCharacter(
    225             webkit_event.windowsKeyCode,
    226             webkit_event.modifiers & WebKit::WebInputEvent::ShiftKey);
    227   } else {
    228     webkit_event.text[0] = webkit_event.unmodifiedText[0];
    229   }
    230 
    231   webkit_event.setKeyIdentifierFromWindowsKeyCode();
    232 
    233   // TODO: IsAutoRepeat/IsKeyPad?
    234 
    235   return webkit_event;
    236 }
    237 
    238 }  // namespace content
    239