1// Copyright 2014 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 "mojo/services/public/cpp/input_events/input_events_type_converters.h"
6
7#if defined(USE_X11)
8#include <X11/extensions/XInput2.h>
9#include <X11/Xlib.h>
10#endif
11
12#include "mojo/services/public/cpp/geometry/geometry_type_converters.h"
13#include "mojo/services/public/cpp/input_events/lib/mojo_extended_key_event_data.h"
14#include "mojo/services/public/interfaces/input_events/input_events.mojom.h"
15#include "ui/events/event_utils.h"
16#include "ui/events/keycodes/keyboard_codes.h"
17
18namespace mojo {
19
20COMPILE_ASSERT(static_cast<int32>(EVENT_FLAGS_NONE) ==
21               static_cast<int32>(ui::EF_NONE),
22               event_flags_should_match);
23COMPILE_ASSERT(static_cast<int32>(EVENT_FLAGS_CAPS_LOCK_DOWN) ==
24               static_cast<int32>(ui::EF_CAPS_LOCK_DOWN),
25               event_flags_should_match);
26COMPILE_ASSERT(static_cast<int32>(EVENT_FLAGS_SHIFT_DOWN) ==
27               static_cast<int32>(ui::EF_SHIFT_DOWN),
28               event_flags_should_match);
29COMPILE_ASSERT(static_cast<int32>(EVENT_FLAGS_CONTROL_DOWN) ==
30               static_cast<int32>(ui::EF_CONTROL_DOWN),
31               event_flags_should_match);
32COMPILE_ASSERT(static_cast<int32>(EVENT_FLAGS_ALT_DOWN) ==
33               static_cast<int32>(ui::EF_ALT_DOWN),
34               event_flags_should_match);
35COMPILE_ASSERT(static_cast<int32>(EVENT_FLAGS_LEFT_MOUSE_BUTTON) ==
36               static_cast<int32>(ui::EF_LEFT_MOUSE_BUTTON),
37               event_flags_should_match);
38COMPILE_ASSERT(static_cast<int32>(EVENT_FLAGS_MIDDLE_MOUSE_BUTTON) ==
39               static_cast<int32>(ui::EF_MIDDLE_MOUSE_BUTTON),
40               event_flags_should_match);
41COMPILE_ASSERT(static_cast<int32>(EVENT_FLAGS_RIGHT_MOUSE_BUTTON) ==
42               static_cast<int32>(ui::EF_RIGHT_MOUSE_BUTTON),
43               event_flags_should_match);
44COMPILE_ASSERT(static_cast<int32>(EVENT_FLAGS_COMMAND_DOWN) ==
45               static_cast<int32>(ui::EF_COMMAND_DOWN),
46               event_flags_should_match);
47COMPILE_ASSERT(static_cast<int32>(EVENT_FLAGS_EXTENDED) ==
48               static_cast<int32>(ui::EF_EXTENDED),
49               event_flags_should_match);
50COMPILE_ASSERT(static_cast<int32>(EVENT_FLAGS_IS_SYNTHESIZED) ==
51               static_cast<int32>(ui::EF_IS_SYNTHESIZED),
52               event_flags_should_match);
53COMPILE_ASSERT(static_cast<int32>(EVENT_FLAGS_ALTGR_DOWN) ==
54               static_cast<int32>(ui::EF_ALTGR_DOWN),
55               event_flags_should_match);
56COMPILE_ASSERT(static_cast<int32>(EVENT_FLAGS_MOD3_DOWN) ==
57               static_cast<int32>(ui::EF_MOD3_DOWN),
58               event_flags_should_match);
59
60
61// static
62EventType TypeConverter<EventType, ui::EventType>::Convert(ui::EventType type) {
63#define MOJO_INPUT_EVENT_NAME(name) case ui::ET_##name: return EVENT_TYPE_##name
64
65  switch (type) {
66#include "mojo/services/public/cpp/input_events/lib/input_event_names.h"
67    case ui::ET_LAST:
68      NOTREACHED();
69      break;
70  }
71
72#undef MOJO_INPUT_EVENT_NAME
73
74  NOTREACHED();
75  return EVENT_TYPE_UNKNOWN;
76}
77
78// static
79ui::EventType TypeConverter<ui::EventType, EventType>::Convert(EventType type) {
80#define MOJO_INPUT_EVENT_NAME(name) case EVENT_TYPE_##name: return ui::ET_##name
81
82  switch (type) {
83#include "mojo/services/public/cpp/input_events/lib/input_event_names.h"
84  }
85
86#undef MOJO_INPUT_EVENT_NAME
87
88  NOTREACHED();
89  return ui::ET_UNKNOWN;
90}
91
92// static
93EventPtr TypeConverter<EventPtr, ui::Event>::Convert(const ui::Event& input) {
94  EventPtr event(Event::New());
95  event->action = ConvertTo<EventType>(input.type());
96  event->flags = EventFlags(input.flags());
97  event->time_stamp = input.time_stamp().ToInternalValue();
98
99  if (input.IsMouseEvent() || input.IsTouchEvent()) {
100    const ui::LocatedEvent* located_event =
101        static_cast<const ui::LocatedEvent*>(&input);
102
103    LocationDataPtr location_data(LocationData::New());
104    location_data->in_view_location = Point::From(located_event->location());
105    if (input.HasNativeEvent()) {
106      location_data->screen_location =
107          Point::From(ui::EventSystemLocationFromNative(input.native_event()));
108    }
109
110    event->location_data = location_data.Pass();
111  }
112
113  if (input.IsTouchEvent()) {
114    const ui::TouchEvent* touch_event =
115        static_cast<const ui::TouchEvent*>(&input);
116    TouchDataPtr touch_data(TouchData::New());
117    touch_data->pointer_id = touch_event->touch_id();
118    event->touch_data = touch_data.Pass();
119  } else if (input.IsKeyEvent()) {
120    const ui::KeyEvent* key_event = static_cast<const ui::KeyEvent*>(&input);
121    KeyDataPtr key_data(KeyData::New());
122    key_data->key_code = key_event->GetConflatedWindowsKeyCode();
123    key_data->native_key_code = key_event->platform_keycode();
124    key_data->is_char = key_event->is_char();
125    key_data->character = key_event->GetCharacter();
126
127    if (key_event->extended_key_event_data()) {
128      const MojoExtendedKeyEventData* data =
129          static_cast<const MojoExtendedKeyEventData*>(
130              key_event->extended_key_event_data());
131      key_data->windows_key_code = static_cast<mojo::KeyboardCode>(
132          data->windows_key_code());
133      key_data->text = data->text();
134      key_data->unmodified_text = data->unmodified_text();
135    } else {
136      key_data->windows_key_code = static_cast<mojo::KeyboardCode>(
137          key_event->GetLocatedWindowsKeyboardCode());
138      key_data->text = key_event->GetText();
139      key_data->unmodified_text = key_event->GetUnmodifiedText();
140    }
141
142    event->key_data = key_data.Pass();
143  } else if (input.IsMouseWheelEvent()) {
144    const ui::MouseWheelEvent* wheel_event =
145        static_cast<const ui::MouseWheelEvent*>(&input);
146    MouseWheelDataPtr wheel_data(MouseWheelData::New());
147    wheel_data->x_offset = wheel_event->x_offset();
148    wheel_data->y_offset = wheel_event->y_offset();
149    event->wheel_data = wheel_data.Pass();
150  }
151  return event.Pass();
152}
153
154// static
155EventPtr TypeConverter<EventPtr, ui::KeyEvent>::Convert(
156    const ui::KeyEvent& input) {
157  return Event::From(static_cast<const ui::Event&>(input));
158}
159
160// static
161scoped_ptr<ui::Event> TypeConverter<scoped_ptr<ui::Event>, EventPtr>::Convert(
162    const EventPtr& input) {
163  scoped_ptr<ui::Event> ui_event;
164  ui::EventType ui_event_type = ConvertTo<ui::EventType>(input->action);
165
166  gfx::Point location;
167  if (!input->location_data.is_null() &&
168      !input->location_data->in_view_location.is_null()) {
169    location = input->location_data->in_view_location.To<gfx::Point>();
170  }
171
172  switch (input->action) {
173    case ui::ET_KEY_PRESSED:
174    case ui::ET_KEY_RELEASED: {
175      scoped_ptr<ui::KeyEvent> key_event;
176      if (input->key_data->is_char) {
177        key_event.reset(new ui::KeyEvent(
178            static_cast<base::char16>(input->key_data->character),
179            static_cast<ui::KeyboardCode>(
180                input->key_data->key_code),
181            input->flags));
182      } else {
183        key_event.reset(new ui::KeyEvent(
184            ui_event_type,
185            static_cast<ui::KeyboardCode>(
186                input->key_data->key_code),
187            input->flags));
188      }
189      key_event->SetExtendedKeyEventData(scoped_ptr<ui::ExtendedKeyEventData>(
190          new MojoExtendedKeyEventData(
191              static_cast<int32_t>(input->key_data->windows_key_code),
192              input->key_data->text,
193              input->key_data->unmodified_text)));
194      key_event->set_platform_keycode(input->key_data->native_key_code);
195      ui_event = key_event.PassAs<ui::KeyEvent>();
196      break;
197    }
198    case EVENT_TYPE_MOUSE_PRESSED:
199    case EVENT_TYPE_MOUSE_DRAGGED:
200    case EVENT_TYPE_MOUSE_RELEASED:
201    case EVENT_TYPE_MOUSE_MOVED:
202    case EVENT_TYPE_MOUSE_ENTERED:
203    case EVENT_TYPE_MOUSE_EXITED: {
204      // TODO: last flags isn't right. Need to send changed_flags.
205      ui_event.reset(new ui::MouseEvent(
206                         ui_event_type,
207                         location,
208                         location,
209                         ui::EventFlags(input->flags),
210                         ui::EventFlags(input->flags)));
211      break;
212    }
213    case EVENT_TYPE_MOUSEWHEEL: {
214      const gfx::Vector2d offset(input->wheel_data->x_offset,
215                                 input->wheel_data->y_offset);
216      ui_event.reset(new ui::MouseWheelEvent(offset,
217                                             location,
218                                             location,
219                                             ui::EventFlags(input->flags),
220                                             ui::EventFlags(input->flags)));
221      break;
222    }
223    case EVENT_TYPE_TOUCH_MOVED:
224    case EVENT_TYPE_TOUCH_PRESSED:
225    case EVENT_TYPE_TOUCH_CANCELLED:
226    case EVENT_TYPE_TOUCH_RELEASED: {
227      ui_event.reset(new ui::TouchEvent(
228                         ui_event_type,
229                         location,
230                         ui::EventFlags(input->flags),
231                         input->touch_data->pointer_id,
232                         base::TimeDelta::FromInternalValue(input->time_stamp),
233                         0.f, 0.f, 0.f, 0.f));
234      break;
235    }
236    default:
237      // TODO: support other types.
238      // NOTIMPLEMENTED();
239      ;
240  }
241  // TODO: need to support time_stamp.
242  return ui_event.Pass();
243}
244
245}  // namespace mojo
246