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.
5 #include "content/browser/renderer_host/web_input_event_aura.h"
7 #include "content/browser/renderer_host/input/web_input_event_util.h"
8 #include "content/browser/renderer_host/ui_events_helper.h"
9 #include "ui/aura/client/screen_position_client.h"
10 #include "ui/aura/window.h"
11 #include "ui/events/blink/blink_event_util.h"
12 #include "ui/events/event.h"
13 #include "ui/events/event_utils.h"
14 #include "ui/events/keycodes/dom4/keycode_converter.h"
20 gfx::Point
GetScreenLocationFromEvent(const ui::LocatedEvent
& event
) {
22 return event
.root_location();
25 static_cast<aura::Window
*>(event
.target())->GetRootWindow();
26 aura::client::ScreenPositionClient
* spc
=
27 aura::client::GetScreenPositionClient(root
);
29 return event
.root_location();
31 gfx::Point
screen_location(event
.root_location());
32 spc
->ConvertPointToScreen(root
, &screen_location
);
33 return screen_location
;
39 blink::WebMouseEvent
MakeUntranslatedWebMouseEventFromNativeEvent(
40 const base::NativeEvent
& native_event
);
41 blink::WebMouseWheelEvent
MakeUntranslatedWebMouseWheelEventFromNativeEvent(
42 const base::NativeEvent
& native_event
);
43 blink::WebKeyboardEvent
MakeWebKeyboardEventFromNativeEvent(
44 const base::NativeEvent
& native_event
);
45 blink::WebGestureEvent
MakeWebGestureEventFromNativeEvent(
46 const base::NativeEvent
& native_event
);
49 blink::WebKeyboardEvent
MakeWebKeyboardEventFromAuraEvent(
50 const ui::KeyEvent
& event
) {
51 blink::WebKeyboardEvent webkit_event
;
53 webkit_event
.timeStampSeconds
= event
.time_stamp().InSecondsF();
54 webkit_event
.modifiers
= ui::EventFlagsToWebEventModifiers(event
.flags());
56 switch (event
.type()) {
57 case ui::ET_KEY_PRESSED
:
58 webkit_event
.type
= event
.is_char() ? blink::WebInputEvent::Char
:
59 blink::WebInputEvent::RawKeyDown
;
61 case ui::ET_KEY_RELEASED
:
62 webkit_event
.type
= blink::WebInputEvent::KeyUp
;
68 if (webkit_event
.modifiers
& blink::WebInputEvent::AltKey
)
69 webkit_event
.isSystemKey
= true;
71 webkit_event
.windowsKeyCode
= event
.GetLocatedWindowsKeyboardCode();
72 webkit_event
.nativeKeyCode
=
73 ui::KeycodeConverter::DomCodeToNativeKeycode(event
.code());
74 webkit_event
.domCode
= static_cast<int>(event
.code());
75 webkit_event
.unmodifiedText
[0] = event
.GetUnmodifiedText();
76 webkit_event
.text
[0] = event
.GetText();
78 webkit_event
.setKeyIdentifierFromWindowsKeyCode();
83 blink::WebMouseWheelEvent
MakeWebMouseWheelEventFromAuraEvent(
84 const ui::ScrollEvent
& event
) {
85 blink::WebMouseWheelEvent webkit_event
;
87 webkit_event
.type
= blink::WebInputEvent::MouseWheel
;
88 webkit_event
.button
= blink::WebMouseEvent::ButtonNone
;
89 webkit_event
.modifiers
= ui::EventFlagsToWebEventModifiers(event
.flags());
90 webkit_event
.timeStampSeconds
= event
.time_stamp().InSecondsF();
91 webkit_event
.hasPreciseScrollingDeltas
= true;
93 float offset_ordinal_x
= 0.f
;
94 float offset_ordinal_y
= 0.f
;
95 if ((event
.flags() & ui::EF_SHIFT_DOWN
) != 0 && event
.x_offset() == 0) {
96 webkit_event
.deltaX
= event
.y_offset();
97 webkit_event
.deltaY
= 0;
98 offset_ordinal_x
= event
.y_offset_ordinal();
99 offset_ordinal_y
= event
.x_offset_ordinal();
101 webkit_event
.deltaX
= event
.x_offset();
102 webkit_event
.deltaY
= event
.y_offset();
103 offset_ordinal_x
= event
.x_offset_ordinal();
104 offset_ordinal_y
= event
.y_offset_ordinal();
107 if (offset_ordinal_x
!= 0.f
&& webkit_event
.deltaX
!= 0.f
)
108 webkit_event
.accelerationRatioX
= offset_ordinal_x
/ webkit_event
.deltaX
;
109 webkit_event
.wheelTicksX
= webkit_event
.deltaX
/ kPixelsPerTick
;
110 webkit_event
.wheelTicksY
= webkit_event
.deltaY
/ kPixelsPerTick
;
111 if (offset_ordinal_y
!= 0.f
&& webkit_event
.deltaY
!= 0.f
)
112 webkit_event
.accelerationRatioY
= offset_ordinal_y
/ webkit_event
.deltaY
;
116 blink::WebGestureEvent
MakeWebGestureEventFromAuraEvent(
117 const ui::ScrollEvent
& event
) {
118 blink::WebGestureEvent webkit_event
;
120 switch (event
.type()) {
121 case ui::ET_SCROLL_FLING_START
:
122 webkit_event
.type
= blink::WebInputEvent::GestureFlingStart
;
123 webkit_event
.data
.flingStart
.velocityX
= event
.x_offset();
124 webkit_event
.data
.flingStart
.velocityY
= event
.y_offset();
126 case ui::ET_SCROLL_FLING_CANCEL
:
127 webkit_event
.type
= blink::WebInputEvent::GestureFlingCancel
;
130 NOTREACHED() << "Invalid gesture type: " << event
.type();
133 NOTREACHED() << "Unknown gesture type: " << event
.type();
136 webkit_event
.sourceDevice
= blink::WebGestureDeviceTouchpad
;
137 webkit_event
.modifiers
= ui::EventFlagsToWebEventModifiers(event
.flags());
138 webkit_event
.timeStampSeconds
= event
.time_stamp().InSecondsF();
142 blink::WebMouseEvent
MakeWebMouseEventFromAuraEvent(
143 const ui::MouseEvent
& event
);
144 blink::WebMouseWheelEvent
MakeWebMouseWheelEventFromAuraEvent(
145 const ui::MouseWheelEvent
& event
);
149 // ui::Event only carries a subset of possible event data provided to Aura by
150 // the host platform. WebKit utilizes a larger subset of that information than
151 // Aura itself. WebKit includes some built in cracking functionality that we
152 // rely on to obtain this information cleanly and consistently.
154 // The only place where an ui::Event's data differs from what the underlying
155 // base::NativeEvent would provide is position data, since we would like to
156 // provide coordinates relative to the aura::Window that is hosting the
157 // renderer, not the top level platform window.
159 // The approach is to fully construct a blink::WebInputEvent from the
160 // ui::Event's base::NativeEvent, and then replace the coordinate fields with
161 // the translated values from the ui::Event.
163 // The exception is mouse events on linux. The ui::MouseEvent contains enough
164 // necessary information to construct a WebMouseEvent. So instead of extracting
165 // the information from the XEvent, which can be tricky when supporting both
166 // XInput2 and XInput, the WebMouseEvent is constructed from the
167 // ui::MouseEvent. This will not be necessary once only XInput2 is supported.
170 blink::WebMouseEvent
MakeWebMouseEvent(const ui::MouseEvent
& event
) {
171 // Construct an untranslated event from the platform event data.
172 blink::WebMouseEvent webkit_event
=
174 // On Windows we have WM_ events comming from desktop and pure aura
175 // events comming from metro mode.
176 event
.native_event().message
?
177 MakeUntranslatedWebMouseEventFromNativeEvent(event
.native_event()) :
178 MakeWebMouseEventFromAuraEvent(event
);
180 MakeWebMouseEventFromAuraEvent(event
);
182 // Replace the event's coordinate fields with translated position data from
184 webkit_event
.windowX
= webkit_event
.x
= event
.x();
185 webkit_event
.windowY
= webkit_event
.y
= event
.y();
188 if (event
.native_event().message
)
191 const gfx::Point screen_point
= GetScreenLocationFromEvent(event
);
192 webkit_event
.globalX
= screen_point
.x();
193 webkit_event
.globalY
= screen_point
.y();
198 blink::WebMouseWheelEvent
MakeWebMouseWheelEvent(
199 const ui::MouseWheelEvent
& event
) {
201 // Construct an untranslated event from the platform event data.
202 blink::WebMouseWheelEvent webkit_event
= event
.native_event().message
?
203 MakeUntranslatedWebMouseWheelEventFromNativeEvent(event
.native_event()) :
204 MakeWebMouseWheelEventFromAuraEvent(event
);
206 blink::WebMouseWheelEvent webkit_event
=
207 MakeWebMouseWheelEventFromAuraEvent(event
);
210 // Replace the event's coordinate fields with translated position data from
212 webkit_event
.windowX
= webkit_event
.x
= event
.x();
213 webkit_event
.windowY
= webkit_event
.y
= event
.y();
215 const gfx::Point screen_point
= GetScreenLocationFromEvent(event
);
216 webkit_event
.globalX
= screen_point
.x();
217 webkit_event
.globalY
= screen_point
.y();
219 // Scroll events generated from the mouse wheel when the control key is held
220 // don't trigger scrolling. Instead, they may cause zooming.
221 bool from_mouse_wheel
= !webkit_event
.hasPreciseScrollingDeltas
;
222 if ((webkit_event
.modifiers
& blink::WebInputEvent::ControlKey
) &&
224 webkit_event
.canScroll
= false;
230 blink::WebMouseWheelEvent
MakeWebMouseWheelEvent(const ui::ScrollEvent
& event
) {
232 // Construct an untranslated event from the platform event data.
233 blink::WebMouseWheelEvent webkit_event
= event
.native_event().message
?
234 MakeUntranslatedWebMouseWheelEventFromNativeEvent(event
.native_event()) :
235 MakeWebMouseWheelEventFromAuraEvent(event
);
237 blink::WebMouseWheelEvent webkit_event
=
238 MakeWebMouseWheelEventFromAuraEvent(event
);
241 // Replace the event's coordinate fields with translated position data from
243 webkit_event
.windowX
= webkit_event
.x
= event
.x();
244 webkit_event
.windowY
= webkit_event
.y
= event
.y();
246 const gfx::Point screen_point
= GetScreenLocationFromEvent(event
);
247 webkit_event
.globalX
= screen_point
.x();
248 webkit_event
.globalY
= screen_point
.y();
253 blink::WebKeyboardEvent
MakeWebKeyboardEvent(const ui::KeyEvent
& event
) {
254 // Windows can figure out whether or not to construct a RawKeyDown or a Char
255 // WebInputEvent based on the type of message carried in
256 // event.native_event(). X11 is not so fortunate, there is no separate
257 // translated event type, so DesktopHostLinux sends an extra KeyEvent with
258 // is_char() == true. We need to pass the ui::KeyEvent to the X11 function
259 // to detect this case so the right event type can be constructed.
261 if (event
.HasNativeEvent()) {
262 // Key events require no translation by the aura system.
263 return MakeWebKeyboardEventFromNativeEvent(event
.native_event());
266 return MakeWebKeyboardEventFromAuraEvent(event
);
269 blink::WebGestureEvent
MakeWebGestureEvent(const ui::GestureEvent
& event
) {
270 blink::WebGestureEvent gesture_event
;
272 if (event
.HasNativeEvent())
273 gesture_event
= MakeWebGestureEventFromNativeEvent(event
.native_event());
275 gesture_event
= MakeWebGestureEventFromUIEvent(event
);
277 gesture_event
= MakeWebGestureEventFromUIEvent(event
);
280 gesture_event
.x
= event
.x();
281 gesture_event
.y
= event
.y();
283 const gfx::Point screen_point
= GetScreenLocationFromEvent(event
);
284 gesture_event
.globalX
= screen_point
.x();
285 gesture_event
.globalY
= screen_point
.y();
287 return gesture_event
;
290 blink::WebGestureEvent
MakeWebGestureEvent(const ui::ScrollEvent
& event
) {
291 blink::WebGestureEvent gesture_event
;
294 gesture_event
= MakeWebGestureEventFromNativeEvent(event
.native_event());
296 gesture_event
= MakeWebGestureEventFromAuraEvent(event
);
299 gesture_event
.x
= event
.x();
300 gesture_event
.y
= event
.y();
302 const gfx::Point screen_point
= GetScreenLocationFromEvent(event
);
303 gesture_event
.globalX
= screen_point
.x();
304 gesture_event
.globalY
= screen_point
.y();
306 return gesture_event
;
309 blink::WebGestureEvent
MakeWebGestureEventFlingCancel() {
310 blink::WebGestureEvent gesture_event
;
312 // All other fields are ignored on a GestureFlingCancel event.
313 gesture_event
.type
= blink::WebInputEvent::GestureFlingCancel
;
314 gesture_event
.sourceDevice
= blink::WebGestureDeviceTouchpad
;
315 return gesture_event
;
318 blink::WebMouseEvent
MakeWebMouseEventFromAuraEvent(
319 const ui::MouseEvent
& event
) {
320 blink::WebMouseEvent webkit_event
;
322 webkit_event
.modifiers
= ui::EventFlagsToWebEventModifiers(event
.flags());
323 webkit_event
.timeStampSeconds
= event
.time_stamp().InSecondsF();
325 webkit_event
.button
= blink::WebMouseEvent::ButtonNone
;
326 int button_flags
= event
.flags();
327 if (event
.type() == ui::ET_MOUSE_PRESSED
||
328 event
.type() == ui::ET_MOUSE_RELEASED
) {
329 // We want to use changed_button_flags() for mouse pressed & released.
330 // These flags can be used only if they are set which is not always the case
331 // (see e.g. GetChangedMouseButtonFlagsFromNative() in events_win.cc).
332 if (event
.changed_button_flags())
333 button_flags
= event
.changed_button_flags();
335 if (button_flags
& ui::EF_LEFT_MOUSE_BUTTON
)
336 webkit_event
.button
= blink::WebMouseEvent::ButtonLeft
;
337 if (button_flags
& ui::EF_MIDDLE_MOUSE_BUTTON
)
338 webkit_event
.button
= blink::WebMouseEvent::ButtonMiddle
;
339 if (button_flags
& ui::EF_RIGHT_MOUSE_BUTTON
)
340 webkit_event
.button
= blink::WebMouseEvent::ButtonRight
;
342 switch (event
.type()) {
343 case ui::ET_MOUSE_PRESSED
:
344 webkit_event
.type
= blink::WebInputEvent::MouseDown
;
345 webkit_event
.clickCount
= event
.GetClickCount();
347 case ui::ET_MOUSE_RELEASED
:
348 webkit_event
.type
= blink::WebInputEvent::MouseUp
;
349 webkit_event
.clickCount
= event
.GetClickCount();
351 case ui::ET_MOUSE_ENTERED
:
352 case ui::ET_MOUSE_EXITED
:
353 case ui::ET_MOUSE_MOVED
:
354 case ui::ET_MOUSE_DRAGGED
:
355 webkit_event
.type
= blink::WebInputEvent::MouseMove
;
358 NOTIMPLEMENTED() << "Received unexpected event: " << event
.type();
365 blink::WebMouseWheelEvent
MakeWebMouseWheelEventFromAuraEvent(
366 const ui::MouseWheelEvent
& event
) {
367 blink::WebMouseWheelEvent webkit_event
;
369 webkit_event
.type
= blink::WebInputEvent::MouseWheel
;
370 webkit_event
.button
= blink::WebMouseEvent::ButtonNone
;
371 webkit_event
.modifiers
= ui::EventFlagsToWebEventModifiers(event
.flags());
372 webkit_event
.timeStampSeconds
= event
.time_stamp().InSecondsF();
374 if ((event
.flags() & ui::EF_SHIFT_DOWN
) != 0 && event
.x_offset() == 0) {
375 webkit_event
.deltaX
= event
.y_offset();
376 webkit_event
.deltaY
= 0;
378 webkit_event
.deltaX
= event
.x_offset();
379 webkit_event
.deltaY
= event
.y_offset();
382 webkit_event
.wheelTicksX
= webkit_event
.deltaX
/ kPixelsPerTick
;
383 webkit_event
.wheelTicksY
= webkit_event
.deltaY
/ kPixelsPerTick
;
388 } // namespace content