1 // Copyright 2013 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.
5 #include "content/browser/renderer_host/input/web_input_event_builders_android.h"
7 #include "base/logging.h"
8 #include "content/browser/renderer_host/input/motion_event_android.h"
9 #include "content/browser/renderer_host/input/web_input_event_util.h"
10 #include "content/browser/renderer_host/input/web_input_event_util_posix.h"
11 #include "ui/events/keycodes/keyboard_code_conversion_android.h"
12 #include "ui/events/keycodes/keyboard_codes_posix.h"
14 using blink::WebInputEvent;
15 using blink::WebKeyboardEvent;
16 using blink::WebGestureEvent;
17 using blink::WebMouseEvent;
18 using blink::WebMouseWheelEvent;
19 using blink::WebTouchEvent;
20 using blink::WebTouchPoint;
25 WebInputEvent::Type ToWebInputEventType(MotionEventAndroid::Action action) {
27 case MotionEventAndroid::ACTION_DOWN:
28 return WebInputEvent::TouchStart;
29 case MotionEventAndroid::ACTION_MOVE:
30 return WebInputEvent::TouchMove;
31 case MotionEventAndroid::ACTION_UP:
32 return WebInputEvent::TouchEnd;
33 case MotionEventAndroid::ACTION_CANCEL:
34 return WebInputEvent::TouchCancel;
35 case MotionEventAndroid::ACTION_POINTER_DOWN:
36 return WebInputEvent::TouchStart;
37 case MotionEventAndroid::ACTION_POINTER_UP:
38 return WebInputEvent::TouchEnd;
40 NOTREACHED() << "Invalid MotionEventAndroid::Action.";
41 return WebInputEvent::Undefined;
44 // Note that |is_action_pointer| is meaningful only in the context of
45 // |ACTION_POINTER_UP| and |ACTION_POINTER_DOWN|; other actions map directly to
46 // WebTouchPoint::State.
47 WebTouchPoint::State ToWebTouchPointState(MotionEventAndroid::Action action,
48 bool is_action_pointer) {
50 case MotionEventAndroid::ACTION_DOWN:
51 return WebTouchPoint::StatePressed;
52 case MotionEventAndroid::ACTION_MOVE:
53 return WebTouchPoint::StateMoved;
54 case MotionEventAndroid::ACTION_UP:
55 return WebTouchPoint::StateReleased;
56 case MotionEventAndroid::ACTION_CANCEL:
57 return WebTouchPoint::StateCancelled;
58 case MotionEventAndroid::ACTION_POINTER_DOWN:
59 return is_action_pointer ? WebTouchPoint::StatePressed
60 : WebTouchPoint::StateStationary;
61 case MotionEventAndroid::ACTION_POINTER_UP:
62 return is_action_pointer ? WebTouchPoint::StateReleased
63 : WebTouchPoint::StateStationary;
65 NOTREACHED() << "Invalid MotionEventAndroid::Action.";
66 return WebTouchPoint::StateUndefined;
69 WebTouchPoint BuildWebTouchPoint(const MotionEventAndroid& event,
73 touch.id = event.GetPointerId(pointer_index);
74 touch.state = ToWebTouchPointState(event.GetActionMasked(),
75 pointer_index == event.GetActionIndex());
76 touch.position.x = event.GetX(pointer_index) / dpi_scale;
77 touch.position.y = event.GetY(pointer_index) / dpi_scale;
78 // TODO(joth): Raw event co-ordinates.
79 touch.screenPosition = touch.position;
81 const int radius_major =
82 static_cast<int>(event.GetTouchMajor(pointer_index) * 0.5f / dpi_scale);
83 const int radius_minor =
84 static_cast<int>(event.GetTouchMinor(pointer_index) * 0.5f / dpi_scale);
85 const float major_angle_in_radians_clockwise_from_vertical =
86 event.GetOrientation();
88 float major_angle_in_degrees_clockwise_from_vertical = 0;
89 if (!std::isnan(major_angle_in_radians_clockwise_from_vertical)) {
90 major_angle_in_degrees_clockwise_from_vertical =
91 major_angle_in_radians_clockwise_from_vertical * 180.f / M_PI;
93 // Android provides a major axis orientation clockwise with respect to the
94 // vertical of [-90, 90]. The proposed W3C extension specifies the angle that
95 // the ellipse described by radiusX and radiusY is rotated clockwise about
96 // its center, with a value of [0, 90], see
97 // http://www.w3.org/TR/2011/WD-touch-events-20110505/.
98 if (major_angle_in_degrees_clockwise_from_vertical >= 0) {
99 touch.radiusX = radius_minor;
100 touch.radiusY = radius_major;
101 touch.rotationAngle = major_angle_in_degrees_clockwise_from_vertical;
103 touch.radiusX = radius_major;
104 touch.radiusY = radius_minor;
105 touch.rotationAngle = major_angle_in_degrees_clockwise_from_vertical + 90.f;
107 DCHECK_GE(touch.rotationAngle, 0.f);
108 DCHECK_LE(touch.rotationAngle, 90.f);
110 touch.force = event.GetPressure(pointer_index);
117 WebKeyboardEvent WebKeyboardEventBuilder::Build(WebInputEvent::Type type,
121 int unicode_character,
122 bool is_system_key) {
123 DCHECK(WebInputEvent::isKeyboardEventType(type));
124 WebKeyboardEvent result;
127 result.modifiers = modifiers;
128 result.timeStampSeconds = time_sec;
129 ui::KeyboardCode windows_key_code =
130 ui::KeyboardCodeFromAndroidKeyCode(keycode);
131 UpdateWindowsKeyCodeAndKeyIdentifier(&result, windows_key_code);
132 result.modifiers |= GetLocationModifiersFromWindowsKeyCode(windows_key_code);
133 result.nativeKeyCode = keycode;
134 result.unmodifiedText[0] = unicode_character;
135 if (result.windowsKeyCode == ui::VKEY_RETURN) {
136 // This is the same behavior as GTK:
137 // We need to treat the enter key as a key press of character \r. This
138 // is apparently just how webkit handles it and what it expects.
139 result.unmodifiedText[0] = '\r';
141 result.text[0] = result.unmodifiedText[0];
142 result.isSystemKey = is_system_key;
147 WebMouseEvent WebMouseEventBuilder::Build(blink::WebInputEvent::Type type,
148 WebMouseEvent::Button button,
154 DCHECK(WebInputEvent::isMouseEventType(type));
155 WebMouseEvent result;
160 result.windowX = window_x;
161 result.windowY = window_y;
162 result.timeStampSeconds = time_sec;
163 result.clickCount = click_count;
164 result.modifiers = modifiers;
166 if (type == WebInputEvent::MouseDown || type == WebInputEvent::MouseUp)
167 result.button = button;
169 result.button = WebMouseEvent::ButtonNone;
174 WebMouseWheelEvent WebMouseWheelEventBuilder::Build(Direction direction,
178 WebMouseWheelEvent result;
180 result.type = WebInputEvent::MouseWheel;
183 result.windowX = window_x;
184 result.windowY = window_y;
185 result.timeStampSeconds = time_sec;
186 result.button = WebMouseEvent::ButtonNone;
188 // The below choices are matched from GTK.
189 const float scrollbar_pixels_per_tick = 160.0f / 3.0f;
193 result.deltaY = scrollbar_pixels_per_tick;
194 result.wheelTicksY = 1;
197 result.deltaY = -scrollbar_pixels_per_tick;
198 result.wheelTicksY = -1;
201 result.deltaX = scrollbar_pixels_per_tick;
202 result.wheelTicksX = 1;
204 case DIRECTION_RIGHT:
205 result.deltaX = -scrollbar_pixels_per_tick;
206 result.wheelTicksX = -1;
213 WebGestureEvent WebGestureEventBuilder::Build(WebInputEvent::Type type,
217 DCHECK(WebInputEvent::isGestureEventType(type));
218 WebGestureEvent result;
223 result.timeStampSeconds = time_sec;
224 result.sourceDevice = WebGestureEvent::Touchscreen;
229 blink::WebTouchEvent WebTouchEventBuilder::Build(jobject motion_event,
231 DCHECK(motion_event);
232 MotionEventAndroid event(motion_event);
234 blink::WebTouchEvent result;
236 result.type = ToWebInputEventType(event.GetActionMasked());
237 DCHECK(WebInputEvent::isTouchEventType(result.type));
239 result.timeStampSeconds =
240 (event.GetEventTime() - base::TimeTicks()).InSecondsF();
242 result.touchesLength =
243 std::min(event.GetPointerCount(),
244 static_cast<size_t>(WebTouchEvent::touchesLengthCap));
245 DCHECK_GT(result.touchesLength, 0U);
247 for (size_t i = 0; i < result.touchesLength; ++i)
248 result.touches[i] = BuildWebTouchPoint(event, i, dpi_scale);
253 } // namespace content