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.
4
5 #include "content/browser/renderer_host/input/web_input_event_util.h"
6
7 #include "base/strings/string_util.h"
8 #include "content/common/input/web_touch_event_traits.h"
9 #include "ui/events/gesture_detection/gesture_event_data.h"
10 #include "ui/events/gesture_detection/motion_event.h"
11
12 using blink::WebGestureEvent;
13 using blink::WebInputEvent;
14 using blink::WebTouchEvent;
15 using blink::WebTouchPoint;
16 using ui::MotionEvent;
17
18 namespace {
19
GetKeyIdentifier(ui::KeyboardCode key_code)20 const char* GetKeyIdentifier(ui::KeyboardCode key_code) {
21 switch (key_code) {
22 case ui::VKEY_MENU:
23 return "Alt";
24 case ui::VKEY_CONTROL:
25 return "Control";
26 case ui::VKEY_SHIFT:
27 return "Shift";
28 case ui::VKEY_CAPITAL:
29 return "CapsLock";
30 case ui::VKEY_LWIN:
31 case ui::VKEY_RWIN:
32 return "Win";
33 case ui::VKEY_CLEAR:
34 return "Clear";
35 case ui::VKEY_DOWN:
36 return "Down";
37 case ui::VKEY_END:
38 return "End";
39 case ui::VKEY_RETURN:
40 return "Enter";
41 case ui::VKEY_EXECUTE:
42 return "Execute";
43 case ui::VKEY_F1:
44 return "F1";
45 case ui::VKEY_F2:
46 return "F2";
47 case ui::VKEY_F3:
48 return "F3";
49 case ui::VKEY_F4:
50 return "F4";
51 case ui::VKEY_F5:
52 return "F5";
53 case ui::VKEY_F6:
54 return "F6";
55 case ui::VKEY_F7:
56 return "F7";
57 case ui::VKEY_F8:
58 return "F8";
59 case ui::VKEY_F9:
60 return "F9";
61 case ui::VKEY_F10:
62 return "F10";
63 case ui::VKEY_F11:
64 return "F11";
65 case ui::VKEY_F12:
66 return "F12";
67 case ui::VKEY_F13:
68 return "F13";
69 case ui::VKEY_F14:
70 return "F14";
71 case ui::VKEY_F15:
72 return "F15";
73 case ui::VKEY_F16:
74 return "F16";
75 case ui::VKEY_F17:
76 return "F17";
77 case ui::VKEY_F18:
78 return "F18";
79 case ui::VKEY_F19:
80 return "F19";
81 case ui::VKEY_F20:
82 return "F20";
83 case ui::VKEY_F21:
84 return "F21";
85 case ui::VKEY_F22:
86 return "F22";
87 case ui::VKEY_F23:
88 return "F23";
89 case ui::VKEY_F24:
90 return "F24";
91 case ui::VKEY_HELP:
92 return "Help";
93 case ui::VKEY_HOME:
94 return "Home";
95 case ui::VKEY_INSERT:
96 return "Insert";
97 case ui::VKEY_LEFT:
98 return "Left";
99 case ui::VKEY_NEXT:
100 return "PageDown";
101 case ui::VKEY_PRIOR:
102 return "PageUp";
103 case ui::VKEY_PAUSE:
104 return "Pause";
105 case ui::VKEY_SNAPSHOT:
106 return "PrintScreen";
107 case ui::VKEY_RIGHT:
108 return "Right";
109 case ui::VKEY_SCROLL:
110 return "Scroll";
111 case ui::VKEY_SELECT:
112 return "Select";
113 case ui::VKEY_UP:
114 return "Up";
115 case ui::VKEY_DELETE:
116 return "U+007F"; // Standard says that DEL becomes U+007F.
117 case ui::VKEY_MEDIA_NEXT_TRACK:
118 return "MediaNextTrack";
119 case ui::VKEY_MEDIA_PREV_TRACK:
120 return "MediaPreviousTrack";
121 case ui::VKEY_MEDIA_STOP:
122 return "MediaStop";
123 case ui::VKEY_MEDIA_PLAY_PAUSE:
124 return "MediaPlayPause";
125 case ui::VKEY_VOLUME_MUTE:
126 return "VolumeMute";
127 case ui::VKEY_VOLUME_DOWN:
128 return "VolumeDown";
129 case ui::VKEY_VOLUME_UP:
130 return "VolumeUp";
131 default:
132 return NULL;
133 };
134 }
135
ToWebInputEventType(MotionEvent::Action action)136 WebInputEvent::Type ToWebInputEventType(MotionEvent::Action action) {
137 switch (action) {
138 case MotionEvent::ACTION_DOWN:
139 return WebInputEvent::TouchStart;
140 case MotionEvent::ACTION_MOVE:
141 return WebInputEvent::TouchMove;
142 case MotionEvent::ACTION_UP:
143 return WebInputEvent::TouchEnd;
144 case MotionEvent::ACTION_CANCEL:
145 return WebInputEvent::TouchCancel;
146 case MotionEvent::ACTION_POINTER_DOWN:
147 return WebInputEvent::TouchStart;
148 case MotionEvent::ACTION_POINTER_UP:
149 return WebInputEvent::TouchEnd;
150 }
151 NOTREACHED() << "Invalid MotionEvent::Action.";
152 return WebInputEvent::Undefined;
153 }
154
155 // Note that |is_action_pointer| is meaningful only in the context of
156 // |ACTION_POINTER_UP| and |ACTION_POINTER_DOWN|; other actions map directly to
157 // WebTouchPoint::State.
ToWebTouchPointState(MotionEvent::Action action,bool is_action_pointer)158 WebTouchPoint::State ToWebTouchPointState(MotionEvent::Action action,
159 bool is_action_pointer) {
160 switch (action) {
161 case MotionEvent::ACTION_DOWN:
162 return WebTouchPoint::StatePressed;
163 case MotionEvent::ACTION_MOVE:
164 return WebTouchPoint::StateMoved;
165 case MotionEvent::ACTION_UP:
166 return WebTouchPoint::StateReleased;
167 case MotionEvent::ACTION_CANCEL:
168 return WebTouchPoint::StateCancelled;
169 case MotionEvent::ACTION_POINTER_DOWN:
170 return is_action_pointer ? WebTouchPoint::StatePressed
171 : WebTouchPoint::StateStationary;
172 case MotionEvent::ACTION_POINTER_UP:
173 return is_action_pointer ? WebTouchPoint::StateReleased
174 : WebTouchPoint::StateStationary;
175 }
176 NOTREACHED() << "Invalid MotionEvent::Action.";
177 return WebTouchPoint::StateUndefined;
178 }
179
CreateWebTouchPoint(const MotionEvent & event,size_t pointer_index)180 WebTouchPoint CreateWebTouchPoint(const MotionEvent& event,
181 size_t pointer_index) {
182 WebTouchPoint touch;
183 touch.id = event.GetPointerId(pointer_index);
184 touch.state = ToWebTouchPointState(
185 event.GetAction(),
186 static_cast<int>(pointer_index) == event.GetActionIndex());
187 touch.position.x = event.GetX(pointer_index);
188 touch.position.y = event.GetY(pointer_index);
189 touch.screenPosition.x = event.GetRawX(pointer_index);
190 touch.screenPosition.y = event.GetRawY(pointer_index);
191 touch.radiusX = touch.radiusY = event.GetTouchMajor(pointer_index) * 0.5f;
192 touch.force = event.GetPressure(pointer_index);
193
194 return touch;
195 }
196
197 } // namespace
198
199 namespace content {
200
UpdateWindowsKeyCodeAndKeyIdentifier(blink::WebKeyboardEvent * event,ui::KeyboardCode windows_key_code)201 void UpdateWindowsKeyCodeAndKeyIdentifier(blink::WebKeyboardEvent* event,
202 ui::KeyboardCode windows_key_code) {
203 event->windowsKeyCode = windows_key_code;
204
205 const char* id = GetKeyIdentifier(windows_key_code);
206 if (id) {
207 base::strlcpy(event->keyIdentifier, id, sizeof(event->keyIdentifier) - 1);
208 } else {
209 base::snprintf(event->keyIdentifier,
210 sizeof(event->keyIdentifier),
211 "U+%04X",
212 base::ToUpperASCII(static_cast<int>(windows_key_code)));
213 }
214 }
215
CreateWebTouchEventFromMotionEvent(const ui::MotionEvent & event)216 blink::WebTouchEvent CreateWebTouchEventFromMotionEvent(
217 const ui::MotionEvent& event) {
218 blink::WebTouchEvent result;
219
220 WebTouchEventTraits::ResetType(
221 ToWebInputEventType(event.GetAction()),
222 (event.GetEventTime() - base::TimeTicks()).InSecondsF(),
223 &result);
224
225 result.touchesLength =
226 std::min(event.GetPointerCount(),
227 static_cast<size_t>(WebTouchEvent::touchesLengthCap));
228 DCHECK_GT(result.touchesLength, 0U);
229
230 for (size_t i = 0; i < result.touchesLength; ++i)
231 result.touches[i] = CreateWebTouchPoint(event, i);
232
233 return result;
234 }
235
CreateWebGestureEventFromGestureEventData(const ui::GestureEventData & data)236 WebGestureEvent CreateWebGestureEventFromGestureEventData(
237 const ui::GestureEventData& data) {
238 WebGestureEvent gesture;
239 gesture.x = data.x;
240 gesture.y = data.y;
241 gesture.globalX = data.raw_x;
242 gesture.globalY = data.raw_y;
243 gesture.timeStampSeconds = (data.time - base::TimeTicks()).InSecondsF();
244 gesture.sourceDevice = blink::WebGestureDeviceTouchscreen;
245
246 switch (data.type()) {
247 case ui::ET_GESTURE_SHOW_PRESS:
248 gesture.type = WebInputEvent::GestureShowPress;
249 gesture.data.showPress.width = data.details.bounding_box_f().width();
250 gesture.data.showPress.height = data.details.bounding_box_f().height();
251 break;
252 case ui::ET_GESTURE_DOUBLE_TAP:
253 gesture.type = WebInputEvent::GestureDoubleTap;
254 DCHECK_EQ(1, data.details.tap_count());
255 gesture.data.tap.tapCount = data.details.tap_count();
256 gesture.data.tap.width = data.details.bounding_box_f().width();
257 gesture.data.tap.height = data.details.bounding_box_f().height();
258 break;
259 case ui::ET_GESTURE_TAP:
260 gesture.type = WebInputEvent::GestureTap;
261 DCHECK_EQ(1, data.details.tap_count());
262 gesture.data.tap.tapCount = data.details.tap_count();
263 gesture.data.tap.width = data.details.bounding_box_f().width();
264 gesture.data.tap.height = data.details.bounding_box_f().height();
265 break;
266 case ui::ET_GESTURE_TAP_UNCONFIRMED:
267 gesture.type = WebInputEvent::GestureTapUnconfirmed;
268 DCHECK_EQ(1, data.details.tap_count());
269 gesture.data.tap.tapCount = data.details.tap_count();
270 gesture.data.tap.width = data.details.bounding_box_f().width();
271 gesture.data.tap.height = data.details.bounding_box_f().height();
272 break;
273 case ui::ET_GESTURE_LONG_PRESS:
274 gesture.type = WebInputEvent::GestureLongPress;
275 gesture.data.longPress.width = data.details.bounding_box_f().width();
276 gesture.data.longPress.height = data.details.bounding_box_f().height();
277 break;
278 case ui::ET_GESTURE_LONG_TAP:
279 gesture.type = WebInputEvent::GestureLongTap;
280 gesture.data.longPress.width = data.details.bounding_box_f().width();
281 gesture.data.longPress.height = data.details.bounding_box_f().height();
282 break;
283 case ui::ET_GESTURE_SCROLL_BEGIN:
284 gesture.type = WebInputEvent::GestureScrollBegin;
285 gesture.data.scrollBegin.deltaXHint = data.details.scroll_x_hint();
286 gesture.data.scrollBegin.deltaYHint = data.details.scroll_y_hint();
287 break;
288 case ui::ET_GESTURE_SCROLL_UPDATE:
289 gesture.type = WebInputEvent::GestureScrollUpdate;
290 gesture.data.scrollUpdate.deltaX = data.details.scroll_x();
291 gesture.data.scrollUpdate.deltaY = data.details.scroll_y();
292 break;
293 case ui::ET_GESTURE_SCROLL_END:
294 gesture.type = WebInputEvent::GestureScrollEnd;
295 break;
296 case ui::ET_SCROLL_FLING_START:
297 gesture.type = WebInputEvent::GestureFlingStart;
298 gesture.data.flingStart.velocityX = data.details.velocity_x();
299 gesture.data.flingStart.velocityY = data.details.velocity_y();
300 break;
301 case ui::ET_SCROLL_FLING_CANCEL:
302 gesture.type = WebInputEvent::GestureFlingCancel;
303 break;
304 case ui::ET_GESTURE_PINCH_BEGIN:
305 gesture.type = WebInputEvent::GesturePinchBegin;
306 break;
307 case ui::ET_GESTURE_PINCH_UPDATE:
308 gesture.type = WebInputEvent::GesturePinchUpdate;
309 gesture.data.pinchUpdate.scale = data.details.scale();
310 break;
311 case ui::ET_GESTURE_PINCH_END:
312 gesture.type = WebInputEvent::GesturePinchEnd;
313 break;
314 case ui::ET_GESTURE_TAP_CANCEL:
315 gesture.type = WebInputEvent::GestureTapCancel;
316 break;
317 case ui::ET_GESTURE_TAP_DOWN:
318 gesture.type = WebInputEvent::GestureTapDown;
319 gesture.data.tapDown.width = data.details.bounding_box_f().width();
320 gesture.data.tapDown.height = data.details.bounding_box_f().height();
321 break;
322 case ui::ET_GESTURE_BEGIN:
323 case ui::ET_GESTURE_END:
324 NOTREACHED() << "ET_GESTURE_BEGIN and ET_GESTURE_END are only produced "
325 << "in Aura, and should never end up here.";
326 break;
327 default:
328 NOTREACHED() << "ui::EventType provided wasn't a valid gesture event.";
329 break;
330 }
331
332 return gesture;
333 }
334
335 } // namespace content
336