chromium/components/input/web_input_event_builders_android.cc

// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/input/web_input_event_builders_android.h"

#include <android/input.h>

#include "base/check.h"
#include "base/time/time.h"
#include "ui/events/android/key_event_utils.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/blink/blink_event_util.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
#include "ui/events/keycodes/keyboard_code_conversion_android.h"
#include "ui/events/keycodes/keyboard_codes_posix.h"

using blink::WebInputEvent;
using blink::WebKeyboardEvent;
using blink::WebGestureEvent;
using blink::WebMouseEvent;
using blink::WebMouseWheelEvent;
using blink::WebPointerProperties;
using blink::WebTouchEvent;
using blink::WebTouchPoint;

namespace input {

namespace {

int WebInputEventToAndroidModifier(int web_modifier) {
  int android_modifier = 0;
  // Currently only Shift, CapsLock are used, add other modifiers if required.
  if (web_modifier & WebInputEvent::kShiftKey)
    android_modifier |= AMETA_SHIFT_ON;
  if (web_modifier & WebInputEvent::kCapsLockOn)
    android_modifier |= AMETA_CAPS_LOCK_ON;
  return android_modifier;
}

ui::DomKey GetDomKeyFromEvent(
    JNIEnv* env,
    const base::android::JavaRef<jobject>& android_key_event,
    int keycode,
    int modifiers,
    int unicode_character) {
  // Synthetic key event, not enough information to get DomKey.
  if (android_key_event.is_null() && !unicode_character)
    return ui::DomKey::UNIDENTIFIED;

  if (!unicode_character && env) {
    // According to spec |kAllowedModifiers| should be Shift and AltGr, however
    // Android doesn't have AltGr key and ImeAdapter::getModifiers won't pass it
    // either.
    // According to discussion we want to honor CapsLock and possibly NumLock as
    // well. https://github.com/w3c/uievents/issues/70
    const int kAllowedModifiers =
        WebInputEvent::kShiftKey | WebInputEvent::kCapsLockOn;
    int fallback_modifiers =
        WebInputEventToAndroidModifier(modifiers & kAllowedModifiers);

    unicode_character = ui::events::android::GetKeyEventUnicodeChar(
        env, android_key_event, fallback_modifiers);
  }

  ui::DomKey key = ui::GetDomKeyFromAndroidEvent(keycode, unicode_character);
  if (key != ui::DomKey::NONE)
    return key;
  return ui::DomKey::UNIDENTIFIED;
}

}  // namespace

WebKeyboardEvent WebKeyboardEventBuilder::Build(
    JNIEnv* env,
    const base::android::JavaRef<jobject>& android_key_event,
    WebInputEvent::Type type,
    int modifiers,
    base::TimeTicks time,
    int keycode,
    int scancode,
    int unicode_character,
    bool is_system_key) {
  DCHECK(WebInputEvent::IsKeyboardEventType(type));

  ui::DomCode dom_code = ui::DomCode::NONE;
  if (scancode)
    dom_code = ui::KeycodeConverter::NativeKeycodeToDomCode(scancode);

  WebKeyboardEvent result(
      type, modifiers | ui::DomCodeToWebInputEventModifiers(dom_code), time);
  result.windows_key_code = ui::LocatedToNonLocatedKeyboardCode(
      ui::KeyboardCodeFromAndroidKeyCode(keycode));
  result.native_key_code = keycode;
  result.dom_code = static_cast<int>(dom_code);
  result.dom_key = GetDomKeyFromEvent(env, android_key_event, keycode,
                                      modifiers, unicode_character);
  result.unmodified_text[0] = unicode_character;
  if (result.windows_key_code == ui::VKEY_RETURN) {
    // This is the same behavior as GTK:
    // We need to treat the enter key as a key press of character \r. This
    // is apparently just how webkit handles it and what it expects.
    result.unmodified_text[0] = '\r';
  }
  result.text[0] = result.unmodified_text[0];
  result.is_system_key = is_system_key;

  return result;
}

WebMouseEvent WebMouseEventBuilder::Build(
    const ui::MotionEventAndroid& motion_event,
    WebInputEvent::Type type,
    int click_count,
    int action_button) {
  DCHECK(WebInputEvent::IsMouseEventType(type));
  int modifiers = motion_event.GetFlags();
  WebMouseEvent result(type, ui::EventFlagsToWebEventModifiers(modifiers),
                       motion_event.GetEventTime());

  result.SetPositionInWidget(motion_event.GetX(0), motion_event.GetY(0));
  result.SetPositionInScreen(motion_event.GetRawX(0), motion_event.GetRawY(0));

  result.click_count = click_count;

  int button = action_button;
  // For events other than MouseDown/Up, action_button is not defined. So we are
  // determining |button| value from |modifiers| as is done in other platforms.
  if (type != WebInputEvent::Type::kMouseDown &&
      type != WebInputEvent::Type::kMouseUp) {
    if (modifiers & ui::EF_LEFT_MOUSE_BUTTON)
      button = ui::MotionEvent::BUTTON_PRIMARY;
    else if (modifiers & ui::EF_MIDDLE_MOUSE_BUTTON)
      button = ui::MotionEvent::BUTTON_TERTIARY;
    else if (modifiers & ui::EF_RIGHT_MOUSE_BUTTON)
      button = ui::MotionEvent::BUTTON_SECONDARY;
    else
      button = 0;
  }

  ui::SetWebPointerPropertiesFromMotionEventData(
      result, motion_event.GetPointerId(0), motion_event.GetPressure(0),
      motion_event.GetOrientation(0), motion_event.GetTiltX(0),
      motion_event.GetTiltY(0), motion_event.GetTwist(0),
      motion_event.GetTangentialPressure(0), button,
      motion_event.GetToolType(0));

  return result;
}

WebMouseWheelEvent WebMouseWheelEventBuilder::Build(
    const ui::MotionEventAndroid& motion_event) {
  WebMouseWheelEvent result(WebInputEvent::Type::kMouseWheel,
                            WebInputEvent::kNoModifiers,
                            motion_event.GetEventTime());
  result.SetPositionInWidget(motion_event.GetX(0), motion_event.GetY(0));
  result.SetPositionInScreen(motion_event.GetRawX(0), motion_event.GetRawY(0));
  result.button = WebMouseEvent::Button::kNoButton;
  result.delta_units = ui::ScrollGranularity::kScrollByPrecisePixel;
  result.delta_x = motion_event.ticks_x() * motion_event.GetTickMultiplier();
  result.delta_y = motion_event.ticks_y() * motion_event.GetTickMultiplier();
  result.wheel_ticks_x = motion_event.ticks_x();
  result.wheel_ticks_y = motion_event.ticks_y();

  return result;
}

WebGestureEvent WebGestureEventBuilder::Build(WebInputEvent::Type type,
                                              base::TimeTicks time,
                                              float x,
                                              float y) {
  DCHECK(WebInputEvent::IsGestureEventType(type));
  WebGestureEvent result(type, WebInputEvent::kNoModifiers, time,
                         blink::WebGestureDevice::kTouchscreen);
  result.SetPositionInWidget(gfx::PointF(x, y));

  return result;
}

}  // namespace input