792f2f76354ccb9357f6220e6cd262171ccfe54c
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / web_input_event_aura.cc
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 #include "content/browser/renderer_host/web_input_event_aura.h"
6
7 #include "content/browser/renderer_host/ui_events_helper.h"
8 #include "ui/aura/window.h"
9 #include "ui/events/event.h"
10 #include "ui/events/event_utils.h"
11
12 #if defined(USE_OZONE)
13 #include "ui/events/keycodes/keyboard_code_conversion.h"
14 #endif
15
16 namespace content {
17
18 #if defined(USE_X11) || defined(USE_OZONE)
19 // From third_party/WebKit/Source/web/gtk/WebInputEventFactory.cpp:
20 blink::WebUChar GetControlCharacter(int windows_key_code, bool shift) {
21   if (windows_key_code >= ui::VKEY_A &&
22     windows_key_code <= ui::VKEY_Z) {
23     // ctrl-A ~ ctrl-Z map to \x01 ~ \x1A
24     return windows_key_code - ui::VKEY_A + 1;
25   }
26   if (shift) {
27     // following graphics chars require shift key to input.
28     switch (windows_key_code) {
29       // ctrl-@ maps to \x00 (Null byte)
30       case ui::VKEY_2:
31         return 0;
32       // ctrl-^ maps to \x1E (Record separator, Information separator two)
33       case ui::VKEY_6:
34         return 0x1E;
35       // ctrl-_ maps to \x1F (Unit separator, Information separator one)
36       case ui::VKEY_OEM_MINUS:
37         return 0x1F;
38       // Returns 0 for all other keys to avoid inputting unexpected chars.
39       default:
40         break;
41     }
42   } else {
43     switch (windows_key_code) {
44       // ctrl-[ maps to \x1B (Escape)
45       case ui::VKEY_OEM_4:
46         return 0x1B;
47       // ctrl-\ maps to \x1C (File separator, Information separator four)
48       case ui::VKEY_OEM_5:
49         return 0x1C;
50       // ctrl-] maps to \x1D (Group separator, Information separator three)
51       case ui::VKEY_OEM_6:
52         return 0x1D;
53       // ctrl-Enter maps to \x0A (Line feed)
54       case ui::VKEY_RETURN:
55         return 0x0A;
56       // Returns 0 for all other keys to avoid inputting unexpected chars.
57       default:
58         break;
59     }
60   }
61   return 0;
62 }
63 #endif
64 #if defined(OS_WIN)
65 blink::WebMouseEvent MakeUntranslatedWebMouseEventFromNativeEvent(
66     base::NativeEvent native_event);
67 blink::WebMouseWheelEvent MakeUntranslatedWebMouseWheelEventFromNativeEvent(
68     base::NativeEvent native_event);
69 blink::WebKeyboardEvent MakeWebKeyboardEventFromNativeEvent(
70     base::NativeEvent native_event);
71 blink::WebGestureEvent MakeWebGestureEventFromNativeEvent(
72     base::NativeEvent native_event);
73 #elif defined(USE_X11)
74 blink::WebKeyboardEvent MakeWebKeyboardEventFromAuraEvent(
75     ui::KeyEvent* event);
76 #elif defined(USE_OZONE)
77 blink::WebKeyboardEvent MakeWebKeyboardEventFromAuraEvent(
78     ui::KeyEvent* event) {
79   const base::NativeEvent& native_event = event->native_event();
80   ui::EventType type = ui::EventTypeFromNative(native_event);
81   blink::WebKeyboardEvent webkit_event;
82
83   webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
84   webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
85
86   switch (type) {
87     case ui::ET_KEY_PRESSED:
88       webkit_event.type = event->is_char() ? blink::WebInputEvent::Char :
89           blink::WebInputEvent::RawKeyDown;
90       break;
91     case ui::ET_KEY_RELEASED:
92       webkit_event.type = blink::WebInputEvent::KeyUp;
93       break;
94     default:
95       NOTREACHED();
96   }
97
98   if (webkit_event.modifiers & blink::WebInputEvent::AltKey)
99     webkit_event.isSystemKey = true;
100
101   wchar_t character = ui::KeyboardCodeFromNative(native_event);
102   webkit_event.windowsKeyCode = character;
103   webkit_event.nativeKeyCode = character;
104
105   if (webkit_event.windowsKeyCode == ui::VKEY_RETURN)
106     webkit_event.unmodifiedText[0] = '\r';
107   else
108     webkit_event.unmodifiedText[0] = ui::GetCharacterFromKeyCode(
109         ui::KeyboardCodeFromNative(native_event),
110         ui::EventFlagsFromNative(native_event));
111
112   if (webkit_event.modifiers & blink::WebInputEvent::ControlKey) {
113     webkit_event.text[0] =
114         GetControlCharacter(
115             webkit_event.windowsKeyCode,
116             webkit_event.modifiers & blink::WebInputEvent::ShiftKey);
117   } else {
118     webkit_event.text[0] = webkit_event.unmodifiedText[0];
119   }
120
121   webkit_event.setKeyIdentifierFromWindowsKeyCode();
122
123   return webkit_event;
124 }
125 #endif
126 #if defined(USE_X11) || defined(USE_OZONE)
127 blink::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent(
128     ui::ScrollEvent* event) {
129   blink::WebMouseWheelEvent webkit_event;
130
131   webkit_event.type = blink::WebInputEvent::MouseWheel;
132   webkit_event.button = blink::WebMouseEvent::ButtonNone;
133   webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
134   webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
135   webkit_event.hasPreciseScrollingDeltas = true;
136
137   float offset_ordinal_x = 0.f;
138   float offset_ordinal_y = 0.f;
139   if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 && event->x_offset() == 0) {
140     webkit_event.deltaX = event->y_offset();
141     webkit_event.deltaY = 0;
142     offset_ordinal_x = event->y_offset_ordinal();
143     offset_ordinal_y = event->x_offset_ordinal();
144   } else {
145     webkit_event.deltaX = event->x_offset();
146     webkit_event.deltaY = event->y_offset();
147     offset_ordinal_x = event->x_offset_ordinal();
148     offset_ordinal_y = event->y_offset_ordinal();
149   }
150
151   if (offset_ordinal_x != 0.f && webkit_event.deltaX != 0.f)
152     webkit_event.accelerationRatioX = offset_ordinal_x / webkit_event.deltaX;
153   webkit_event.wheelTicksX = webkit_event.deltaX / kPixelsPerTick;
154   webkit_event.wheelTicksY = webkit_event.deltaY / kPixelsPerTick;
155   if (offset_ordinal_y != 0.f && webkit_event.deltaY != 0.f)
156     webkit_event.accelerationRatioY = offset_ordinal_y / webkit_event.deltaY;
157   return webkit_event;
158 }
159
160 blink::WebGestureEvent MakeWebGestureEventFromAuraEvent(
161     ui::ScrollEvent* event) {
162   blink::WebGestureEvent webkit_event;
163
164   switch (event->type()) {
165     case ui::ET_SCROLL_FLING_START:
166       webkit_event.type = blink::WebInputEvent::GestureFlingStart;
167       webkit_event.data.flingStart.velocityX = event->x_offset();
168       webkit_event.data.flingStart.velocityY = event->y_offset();
169       break;
170     case ui::ET_SCROLL_FLING_CANCEL:
171       webkit_event.type = blink::WebInputEvent::GestureFlingCancel;
172       break;
173     case ui::ET_SCROLL:
174       NOTREACHED() << "Invalid gesture type: " << event->type();
175       break;
176     default:
177       NOTREACHED() << "Unknown gesture type: " << event->type();
178   }
179
180   webkit_event.sourceDevice = blink::WebGestureEvent::Touchpad;
181   webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
182   webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
183   return webkit_event;
184 }
185
186 #endif
187
188 blink::WebMouseEvent MakeWebMouseEventFromAuraEvent(
189     ui::MouseEvent* event);
190 blink::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent(
191     ui::MouseWheelEvent* event);
192
193 // General approach:
194 //
195 // ui::Event only carries a subset of possible event data provided to Aura by
196 // the host platform. WebKit utilizes a larger subset of that information than
197 // Aura itself. WebKit includes some built in cracking functionality that we
198 // rely on to obtain this information cleanly and consistently.
199 //
200 // The only place where an ui::Event's data differs from what the underlying
201 // base::NativeEvent would provide is position data, since we would like to
202 // provide coordinates relative to the aura::Window that is hosting the
203 // renderer, not the top level platform window.
204 //
205 // The approach is to fully construct a blink::WebInputEvent from the
206 // ui::Event's base::NativeEvent, and then replace the coordinate fields with
207 // the translated values from the ui::Event.
208 //
209 // The exception is mouse events on linux. The ui::MouseEvent contains enough
210 // necessary information to construct a WebMouseEvent. So instead of extracting
211 // the information from the XEvent, which can be tricky when supporting both
212 // XInput2 and XInput, the WebMouseEvent is constructed from the
213 // ui::MouseEvent. This will not be necessary once only XInput2 is supported.
214 //
215
216 blink::WebMouseEvent MakeWebMouseEvent(ui::MouseEvent* event) {
217   // Construct an untranslated event from the platform event data.
218   blink::WebMouseEvent webkit_event =
219 #if defined(OS_WIN)
220   // On Windows we have WM_ events comming from desktop and pure aura
221   // events comming from metro mode.
222   event->native_event().message ?
223       MakeUntranslatedWebMouseEventFromNativeEvent(event->native_event()) :
224       MakeWebMouseEventFromAuraEvent(event);
225 #else
226   MakeWebMouseEventFromAuraEvent(event);
227 #endif
228   // Replace the event's coordinate fields with translated position data from
229   // |event|.
230   webkit_event.windowX = webkit_event.x = event->x();
231   webkit_event.windowY = webkit_event.y = event->y();
232
233 #if defined(OS_WIN)
234   if (event->native_event().message)
235     return webkit_event;
236 #endif
237   const gfx::Point root_point = event->root_location();
238   webkit_event.globalX = root_point.x();
239   webkit_event.globalY = root_point.y();
240
241   return webkit_event;
242 }
243
244 blink::WebMouseWheelEvent MakeWebMouseWheelEvent(ui::MouseWheelEvent* event) {
245 #if defined(OS_WIN)
246   // Construct an untranslated event from the platform event data.
247   blink::WebMouseWheelEvent webkit_event = event->native_event().message ?
248       MakeUntranslatedWebMouseWheelEventFromNativeEvent(event->native_event()) :
249       MakeWebMouseWheelEventFromAuraEvent(event);
250 #else
251   blink::WebMouseWheelEvent webkit_event =
252       MakeWebMouseWheelEventFromAuraEvent(event);
253 #endif
254
255   // Replace the event's coordinate fields with translated position data from
256   // |event|.
257   webkit_event.windowX = webkit_event.x = event->x();
258   webkit_event.windowY = webkit_event.y = event->y();
259
260   const gfx::Point root_point = event->root_location();
261   webkit_event.globalX = root_point.x();
262   webkit_event.globalY = root_point.y();
263
264   return webkit_event;
265 }
266
267 blink::WebMouseWheelEvent MakeWebMouseWheelEvent(ui::ScrollEvent* event) {
268 #if defined(OS_WIN)
269   // Construct an untranslated event from the platform event data.
270   blink::WebMouseWheelEvent webkit_event =
271       MakeUntranslatedWebMouseWheelEventFromNativeEvent(event->native_event());
272 #else
273   blink::WebMouseWheelEvent webkit_event =
274       MakeWebMouseWheelEventFromAuraEvent(event);
275 #endif
276
277   // Replace the event's coordinate fields with translated position data from
278   // |event|.
279   webkit_event.windowX = webkit_event.x = event->x();
280   webkit_event.windowY = webkit_event.y = event->y();
281
282   const gfx::Point root_point = event->root_location();
283   webkit_event.globalX = root_point.x();
284   webkit_event.globalY = root_point.y();
285
286   return webkit_event;
287 }
288
289 blink::WebKeyboardEvent MakeWebKeyboardEvent(ui::KeyEvent* event) {
290   if (!event->HasNativeEvent())
291     return blink::WebKeyboardEvent();
292
293   // Windows can figure out whether or not to construct a RawKeyDown or a Char
294   // WebInputEvent based on the type of message carried in
295   // event->native_event(). X11 is not so fortunate, there is no separate
296   // translated event type, so DesktopHostLinux sends an extra KeyEvent with
297   // is_char() == true. We need to pass the ui::KeyEvent to the X11 function
298   // to detect this case so the right event type can be constructed.
299 #if defined(OS_WIN)
300   // Key events require no translation by the aura system.
301   return MakeWebKeyboardEventFromNativeEvent(event->native_event());
302 #else
303   return MakeWebKeyboardEventFromAuraEvent(event);
304 #endif
305 }
306
307 blink::WebGestureEvent MakeWebGestureEvent(ui::GestureEvent* event) {
308   blink::WebGestureEvent gesture_event;
309 #if defined(OS_WIN)
310   if (event->HasNativeEvent())
311     gesture_event = MakeWebGestureEventFromNativeEvent(event->native_event());
312   else
313     gesture_event = MakeWebGestureEventFromUIEvent(*event);
314 #else
315   gesture_event = MakeWebGestureEventFromUIEvent(*event);
316 #endif
317
318   gesture_event.x = event->x();
319   gesture_event.y = event->y();
320
321   const gfx::Point root_point = event->root_location();
322   gesture_event.globalX = root_point.x();
323   gesture_event.globalY = root_point.y();
324
325   return gesture_event;
326 }
327
328 blink::WebGestureEvent MakeWebGestureEvent(ui::ScrollEvent* event) {
329   blink::WebGestureEvent gesture_event;
330
331 #if defined(OS_WIN)
332   gesture_event = MakeWebGestureEventFromNativeEvent(event->native_event());
333 #else
334   gesture_event = MakeWebGestureEventFromAuraEvent(event);
335 #endif
336
337   gesture_event.x = event->x();
338   gesture_event.y = event->y();
339
340   const gfx::Point root_point = event->root_location();
341   gesture_event.globalX = root_point.x();
342   gesture_event.globalY = root_point.y();
343
344   return gesture_event;
345 }
346
347 blink::WebGestureEvent MakeWebGestureEventFlingCancel() {
348   blink::WebGestureEvent gesture_event;
349
350   // All other fields are ignored on a GestureFlingCancel event.
351   gesture_event.type = blink::WebInputEvent::GestureFlingCancel;
352   gesture_event.sourceDevice = blink::WebGestureEvent::Touchpad;
353   return gesture_event;
354 }
355
356 blink::WebMouseEvent MakeWebMouseEventFromAuraEvent(ui::MouseEvent* event) {
357   blink::WebMouseEvent webkit_event;
358
359   webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
360   webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
361
362   webkit_event.button = blink::WebMouseEvent::ButtonNone;
363   if (event->flags() & ui::EF_LEFT_MOUSE_BUTTON)
364     webkit_event.button = blink::WebMouseEvent::ButtonLeft;
365   if (event->flags() & ui::EF_MIDDLE_MOUSE_BUTTON)
366     webkit_event.button = blink::WebMouseEvent::ButtonMiddle;
367   if (event->flags() & ui::EF_RIGHT_MOUSE_BUTTON)
368     webkit_event.button = blink::WebMouseEvent::ButtonRight;
369
370   switch (event->type()) {
371     case ui::ET_MOUSE_PRESSED:
372       webkit_event.type = blink::WebInputEvent::MouseDown;
373       webkit_event.clickCount = event->GetClickCount();
374       break;
375     case ui::ET_MOUSE_RELEASED:
376       webkit_event.type = blink::WebInputEvent::MouseUp;
377       webkit_event.clickCount = event->GetClickCount();
378       break;
379     case ui::ET_MOUSE_ENTERED:
380     case ui::ET_MOUSE_EXITED:
381     case ui::ET_MOUSE_MOVED:
382     case ui::ET_MOUSE_DRAGGED:
383       webkit_event.type = blink::WebInputEvent::MouseMove;
384       break;
385     default:
386       NOTIMPLEMENTED() << "Received unexpected event: " << event->type();
387       break;
388   }
389
390   return webkit_event;
391 }
392
393 blink::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent(
394     ui::MouseWheelEvent* event) {
395   blink::WebMouseWheelEvent webkit_event;
396
397   webkit_event.type = blink::WebInputEvent::MouseWheel;
398   webkit_event.button = blink::WebMouseEvent::ButtonNone;
399   webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
400   webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
401
402   if ((event->flags() & ui::EF_SHIFT_DOWN) != 0 && event->x_offset() == 0) {
403     webkit_event.deltaX = event->y_offset();
404     webkit_event.deltaY = 0;
405   } else {
406     webkit_event.deltaX = event->x_offset();
407     webkit_event.deltaY = event->y_offset();
408   }
409
410   webkit_event.wheelTicksX = webkit_event.deltaX / kPixelsPerTick;
411   webkit_event.wheelTicksY = webkit_event.deltaY / kPixelsPerTick;
412
413   return webkit_event;
414 }
415
416 }  // namespace content