[M120 Migration][VD] Fix some focus issues for offscreen mode
[platform/framework/web/chromium-efl.git] / tizen_src / chromium_impl / ui / ozone / platform / efl / efl_event_handler.cc
1 // Copyright 2021 Samsung Electronics. 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 "ui/ozone/platform/efl/efl_event_handler.h"
6 #include "ui/display/screen.h"
7
8 #include "base/logging.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "build/build_config.h"
12 #include "tizen/system_info.h"
13 #include "ui/base/ime/linux/linux_input_method_context_factory.h"
14 #include "ui/events/base_event_utils.h"
15 #include "ui/events/event.h"
16 #include "ui/events/types/event_type.h"
17 #include "ui/gfx/geometry/point_f.h"
18 #include "ui/ozone/platform/efl/efl_keycode_map.h"
19 #include "ui/ozone/platform/efl/efl_platform_event_source.h"
20 #include "ui/ozone/platform/efl/efl_window.h"
21 #include "ui/ozone/platform/efl/im_context_efl.h"
22
23 #if BUILDFLAG(IS_TIZEN)
24 #include "ui/events/keycodes/dom/dom_code.h"
25 #include "ui/events/keycodes/dom/dom_key.h"
26 #include "ui/events/keycodes/dom/keycode_converter.h"
27 #include "ui/events/keycodes/keyboard_code_conversion.h"
28 #endif
29
30 #if BUILDFLAG(IS_TIZEN_TV)
31 #include "base/base_switches.h"
32 #include "base/command_line.h"
33 #include "third_party/blink/public/platform/web_application_type.h"
34 #endif
35
36 namespace ui {
37
38 namespace {
39 const float kDefaultScrollStep = 20;
40
41 inline bool string_ends_with(std::string const& value,
42                              std::string const& match) {
43   if (match.size() > value.size()) {
44     return false;
45   }
46   return std::equal(match.rbegin(), match.rend(), value.rbegin());
47 }
48
49 inline bool string_starts_with(std::string const& value,
50                                std::string const& match) {
51   if (match.size() > value.size()) {
52     return false;
53   }
54   return std::equal(match.begin(), match.end(), value.begin());
55 }
56
57 // TV RC device names
58 const std::string kDeviceNameSmartView = "SMART_VIEW";
59 const std::string kDeviceNamePanelKey = "wt61p807 panel key device";
60 const std::string kDeviceNameRemote = "wt61p807 rc device";
61 const std::string kDeviceNameSmartRC = "Smart Control";
62 // To allow to receive Tomato send key events
63 const std::string kDeviceNameAutoModeDevice = "AUTO_MODE_DEVICE";
64 const std::string kDeviceNameIME = "ime";
65
66 bool IsRCDevice(Evas_Device_Class device_id, const std::string device_name) {
67   if (device_id == EVAS_DEVICE_CLASS_KEYBOARD) {
68     if (!device_name.compare(kDeviceNameRemote) ||
69         !device_name.compare(kDeviceNameSmartView) ||
70         !device_name.compare(kDeviceNamePanelKey) ||
71         !device_name.compare(kDeviceNameAutoModeDevice) ||
72         device_name.find(kDeviceNameSmartRC) != std::string::npos)
73       return true;
74   }
75   return false;
76 }
77
78 enum { kLeftButton = 1, kMiddleButton = 2, kRightButton = 3 };
79
80 EventFlags EvasToUIMouseButton(int button) {
81   if (button == kLeftButton)
82     return EF_LEFT_MOUSE_BUTTON;
83   if (button == kMiddleButton)
84     return EF_MIDDLE_MOUSE_BUTTON;
85   if (button == kRightButton)
86     return EF_RIGHT_MOUSE_BUTTON;
87
88   return EF_NONE;
89 }
90
91 int GetEventFlagsFromKey(const char* key) {
92   int flags = 0;
93   if (base::StartsWith(key, "Shift", base::CompareCase::SENSITIVE))
94     flags |= EF_SHIFT_DOWN;
95   if (base::StartsWith(key, "Control", base::CompareCase::SENSITIVE))
96     flags |= EF_CONTROL_DOWN;
97   if (base::StartsWith(key, "Alt", base::CompareCase::SENSITIVE))
98     flags |= EF_ALT_DOWN;
99   if (base::StartsWith(key, "Meta", base::CompareCase::SENSITIVE))
100     flags |= EF_COMMAND_DOWN;
101   if (base::StartsWith(key, "Super", base::CompareCase::SENSITIVE))
102     flags |= EF_COMMAND_DOWN;
103
104   return flags;
105 }
106
107 int EvasModifiersToEventFlags(const Evas_Modifier* modifiers,
108                               bool check_super = true) {
109   int flags = 0;
110   if (evas_key_modifier_is_set(modifiers, "Shift"))
111     flags |= EF_SHIFT_DOWN;
112   if (evas_key_modifier_is_set(modifiers, "Control"))
113     flags |= EF_CONTROL_DOWN;
114   if (evas_key_modifier_is_set(modifiers, "Alt"))
115     flags |= EF_ALT_DOWN;
116   if (evas_key_modifier_is_set(modifiers, "Meta"))
117     flags |= EF_COMMAND_DOWN;
118   if (evas_key_modifier_is_set(modifiers, "Super") && check_super)
119     flags |= EF_COMMAND_DOWN;
120
121   return flags;
122 }
123
124 static EventType EvasTouchEventTypeToUI(Evas_Touch_Point_State evas_touch) {
125   switch (evas_touch) {
126     case EVAS_TOUCH_POINT_DOWN:
127       return ET_TOUCH_PRESSED;
128     case EVAS_TOUCH_POINT_MOVE:
129       return ET_TOUCH_MOVED;
130     case EVAS_TOUCH_POINT_UP:
131       return ET_TOUCH_RELEASED;
132     case EVAS_TOUCH_POINT_CANCEL:
133       return ET_TOUCH_CANCELLED;
134     case EVAS_TOUCH_POINT_STILL:
135     // Not handled by chromium, should not be passed here.
136     default:
137       NOTREACHED();
138       return ET_UNKNOWN;
139   }
140 }
141
142 float GetDeviceScaleFactor() {
143   static float device_scale_factor = 0.0f;
144   if (!device_scale_factor) {
145     device_scale_factor =
146         display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
147   }
148   return device_scale_factor;
149 }
150
151 }  // namespace
152
153 EflEventHandler::EflEventHandler(EflWindow* window)
154     : window_(window), events_overlay_(window->native_view()) {
155   if (IsMobileProfile())
156     touch_events_enabled_ = true;
157
158   RegisterCallbacks();
159 }
160
161 EflEventHandler::~EflEventHandler() {
162   if (mouse_events_enabled_)
163     DeleteMouseCallbacks();
164
165   if (key_events_enabled_)
166     DeleteKeyCallbacks();
167
168   if (touch_events_enabled_)
169     DeleteTouchCallbacks();
170 }
171
172 void EflEventHandler::RegisterCallbacks() {
173   if (mouse_events_enabled_)
174     AddMouseCallbacks();
175
176   if (key_events_enabled_)
177     AddKeyCallbacks();
178
179 #if BUILDFLAG(IS_TIZEN_TV)
180   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
181           switches::kEnableOffscreenRendering))
182 #endif
183     evas_object_focus_set(events_overlay_, EINA_TRUE);
184
185   if (touch_events_enabled_)
186     AddTouchCallbacks();
187 }
188
189 int EflEventHandler::GetTopControlsHeight() {
190   int top_controls_height = 0;
191   evas_object_geometry_get(events_overlay_, nullptr, &top_controls_height,
192                            nullptr, nullptr);
193   return top_controls_height;
194 }
195
196 template <typename EVT>
197 bool EflEventHandler::GetTouchEventsEnabled(const EVT* evas_evt) {
198 #if BUILDFLAG(IS_TIZEN_TV)
199   return (touch_events_enabled_ &&
200           evas_device_class_get(evas_evt->dev) == EVAS_DEVICE_CLASS_TOUCH);
201 #endif
202   return touch_events_enabled_;
203 }
204
205 template <class EVT>
206 MouseEvent MakeWebMouseEvent(EventType type, const EVT* ev, int delta_y) {
207   gfx::PointF location(ev->canvas.x, ev->canvas.y);
208   location.Offset(0, -delta_y);
209   int button = EvasToUIMouseButton(ev->button);
210   int event_flags = EvasModifiersToEventFlags(ev->modifiers);
211   event_flags |= button;
212   MouseEvent event(type, location, location, base::TimeTicks::Now(),
213                    event_flags, button);
214
215 #if BUILDFLAG(IS_TIZEN_TV)
216   int clickCount = 1;
217   if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)  // dblclick
218     clickCount = 2;
219   if (ev->flags & EVAS_BUTTON_TRIPLE_CLICK)  // triple click
220     clickCount = 3;
221
222   event.SetClickCount(clickCount);
223 #endif
224
225   return event;
226 }
227
228 TouchEvent MakeTouchEvent(Evas_Coord_Point pt,
229                           Evas_Touch_Point_State state,
230                           int id,
231                           unsigned int timestamp,
232                           int delta_y) {
233   base::TimeTicks event_timestamp = base::TimeTicks::FromInternalValue(
234       timestamp * base::Time::kMicrosecondsPerMillisecond);
235
236   if (timestamp == 0)
237     event_timestamp = EventTimeForNow();
238
239   pt.y -= delta_y;
240
241   TouchEvent touch_event(
242       EvasTouchEventTypeToUI(state), gfx::Point(), event_timestamp,
243       PointerDetails(EventPointerType::kTouch, id, 0.0f, 0.0f, 0.0f));
244   gfx::PointF point(pt.x, pt.y);
245   touch_event.set_location_f(point);
246   touch_event.set_root_location_f(point);
247   return touch_event;
248 }
249
250 template <class EVT>
251 KeyEvent MakeWebKeyEvent(bool pressed, const EVT* evt) {
252   EventType type = pressed ? ET_KEY_PRESSED : ET_KEY_RELEASED;
253   int native_key_code = evt->keycode;
254   KeyboardCode windows_key_code = UIKeyCodeFromEflKey(evt->key);
255
256   int flags = 0;
257 #if BUILDFLAG(IS_TIZEN_TV)
258   // On combinate key "shift+Alt+xxx", the "key" of the "Alt" is
259   // "Meta_L/Meta_R", not the "Alt_L/Alt_R", so use the keyname replace the
260   // "key" to get the flag.
261   if (evt->keyname)
262     flags = GetEventFlagsFromKey(evt->keyname);
263   else
264 #endif
265     flags = GetEventFlagsFromKey(evt->key);
266
267   int key_modifiers = 0;
268   if (evas_key_lock_is_set(evt->locks, "Caps_Lock"))
269     key_modifiers |= EF_CAPS_LOCK_ON;
270
271   key_modifiers |= EvasModifiersToEventFlags(evt->modifiers);
272
273   // For Modifiers Key, need set the modifier when key press,
274   // no need set the modifier when key release.
275   // refer w3c spec: https://w3c.github.io/uievents/#keys-modifierss
276   if (pressed)
277     key_modifiers |= flags;
278   else
279     key_modifiers &= ~flags;
280
281 #if BUILDFLAG(IS_TIZEN)
282   DomCode domCode = KeycodeConverter::NativeKeycodeToDomCode(native_key_code);
283
284   DomKey domKey = KeycodeConverter::KeyStringToDomKey(evt->key);
285   // If the efl key name is not identified, use its domcode to find it in domkey
286   // map
287   if ((domKey == DomKey::NONE) && (domCode != DomCode::NONE)) {
288     int flags = key_modifiers;
289     KeyboardCode windowsKeyCode = VKEY_UNKNOWN;
290     std::ignore =
291         DomCodeToUsLayoutDomKey(domCode, flags, &domKey, &windowsKeyCode);
292   }
293
294   KeyEvent event(type, windows_key_code, domCode, key_modifiers, domKey,
295                  base::TimeTicks::Now(), false);
296 #if BUILDFLAG(IS_TIZEN_TV)
297   const char* device_name = evas_device_name_get(evt->dev);
298   if (device_name) {
299     // We need distinguish if key is from RC in render process
300     if (IsRCDevice(evas_device_class_get(evt->dev), device_name))
301       event.is_from_rc = true;
302
303     // Add device name property in keyboard event.
304     event.device_name = device_name;
305   }
306 #endif
307
308 #else
309   KeyEvent event(type, windows_key_code, key_modifiers, base::TimeTicks::Now());
310 #endif
311
312   return event;
313 }
314
315 template KeyEvent MakeWebKeyEvent(bool, const Evas_Event_Key_Down*);
316 template KeyEvent MakeWebKeyEvent(bool, const Evas_Event_Key_Up*);
317
318 void EflEventHandler::SetMouseEventsEnabled(bool enabled) {
319   if (mouse_events_enabled_ == enabled)
320     return;
321
322   mouse_events_enabled_ = enabled;
323
324   LOG(INFO) << "SetMouseEventsEnabled: " << (enabled ? "enabled" : "disabled");
325   if (enabled)
326     AddMouseCallbacks();
327   else
328     DeleteMouseCallbacks();
329 }
330
331 void EflEventHandler::SetTouchEventsEnabled(bool enabled) {
332   if (touch_events_enabled_ == enabled)
333     return;
334
335   touch_events_enabled_ = enabled;
336
337   LOG(INFO) << "SetTouchEventsEnabled: " << (enabled ? "enabled" : "disabled");
338   if (enabled)
339     AddTouchCallbacks();
340   else
341     DeleteTouchCallbacks();
342 }
343
344 void EflEventHandler::SetKeyEventsEnabled(bool enabled) {
345   if (key_events_enabled_ == enabled)
346     return;
347
348   key_events_enabled_ = enabled;
349
350   LOG(INFO) << "SetKeyEventsEnabled: " << (enabled ? "enabled" : "disabled");
351   if (enabled)
352     AddKeyCallbacks();
353   else
354     DeleteKeyCallbacks();
355 }
356
357 void EflEventHandler::SendKeyEvent(Evas_Object* ewk_view,
358                                    void* event_info,
359                                    bool is_press) {
360   if (is_press) {
361     OnKeyDown(static_cast<void*>(this), nullptr, ewk_view, event_info);
362   } else {
363     OnKeyUp(static_cast<void*>(this), nullptr, ewk_view, event_info);
364   }
365 }
366
367 static int mouse_pre_x = 0;
368 static int mouse_pre_y = 0;
369
370 void EflEventHandler::SendMouseDown(int button, int x, int y) {
371   Evas_Event_Mouse_Down ev;
372   ev.button = button;
373   ev.flags = EVAS_BUTTON_NONE;
374   ev.canvas.x = x;
375   ev.canvas.y = y;
376   ev.modifiers = 0;
377   ev.timestamp = ecore_time_get();
378
379   OnMouseDown(static_cast<void*>(this), window_->evas(), events_overlay_, &ev);
380 }
381
382 void EflEventHandler::SendMouseUp(int button, int x, int y) {
383   Evas_Event_Mouse_Up ev;
384   ev.button = button;
385   ev.flags = EVAS_BUTTON_NONE;
386   ev.canvas.x = x;
387   ev.canvas.y = y;
388   ev.modifiers = 0;
389   ev.timestamp = ecore_time_get();
390
391   OnMouseUp(static_cast<void*>(this), window_->evas(), events_overlay_, &ev);
392 }
393
394 void EflEventHandler::SendMouseMove(int x, int y) {
395   Evas_Event_Mouse_Move ev;
396   ev.buttons = 1;
397   ev.cur.canvas.x = x;
398   ev.cur.canvas.y = y;
399   ev.prev.canvas.x = mouse_pre_x;
400   ev.prev.canvas.y = mouse_pre_y;
401   ev.modifiers = 0;
402   ev.timestamp = ecore_time_get();
403
404   OnMouseMove(static_cast<void*>(this), window_->evas(), events_overlay_, &ev);
405
406   mouse_pre_x = x;
407   mouse_pre_y = y;
408 }
409
410 void EflEventHandler::SendMouseWheel(bool y_direction, int step, int x, int y) {
411   Evas_Event_Mouse_Wheel ev;
412   ev.direction = y_direction ? 0 : 1;
413   ev.canvas.x = x;
414   ev.canvas.y = y;
415   ev.z = step;
416   ev.modifiers = 0;
417   ev.timestamp = ecore_time_get();
418
419   OnMouseWheel(static_cast<void*>(this), window_->evas(), events_overlay_, &ev);
420 }
421
422 void EflEventHandler::SendMouseIn() {
423   OnMouseIn(static_cast<void*>(this), nullptr, nullptr, nullptr);
424 }
425
426 void EflEventHandler::SendMouseOut() {
427   Evas_Event_Mouse_Out ev;
428   ev.buttons = 0;
429   ev.canvas.x = mouse_pre_x;
430   ev.canvas.y = mouse_pre_y;
431   ev.modifiers = 0;
432   ev.timestamp = ecore_time_get();
433
434   OnMouseOut(static_cast<void*>(this), window_->evas(), events_overlay_, &ev);
435 }
436
437 void EflEventHandler::AddMouseCallbacks() {
438   evas_object_event_callback_add(events_overlay_, EVAS_CALLBACK_MOUSE_DOWN,
439                                  OnMouseDown, this);
440   evas_object_event_callback_add(events_overlay_, EVAS_CALLBACK_MOUSE_UP,
441                                  OnMouseUp, this);
442   evas_object_event_callback_add(events_overlay_, EVAS_CALLBACK_MOUSE_MOVE,
443                                  OnMouseMove, this);
444   evas_object_event_callback_add(events_overlay_, EVAS_CALLBACK_MOUSE_IN,
445                                  OnMouseIn, this);
446   evas_object_event_callback_add(events_overlay_, EVAS_CALLBACK_MOUSE_OUT,
447                                  OnMouseOut, this);
448   evas_object_event_callback_add(events_overlay_, EVAS_CALLBACK_MOUSE_WHEEL,
449                                  OnMouseWheel, this);
450 }
451
452 void EflEventHandler::DeleteMouseCallbacks() {
453   evas_object_event_callback_del(events_overlay_, EVAS_CALLBACK_MOUSE_DOWN,
454                                  OnMouseDown);
455   evas_object_event_callback_del(events_overlay_, EVAS_CALLBACK_MOUSE_UP,
456                                  OnMouseUp);
457   evas_object_event_callback_del(events_overlay_, EVAS_CALLBACK_MOUSE_MOVE,
458                                  OnMouseMove);
459   evas_object_event_callback_del(events_overlay_, EVAS_CALLBACK_MOUSE_IN,
460                                  OnMouseIn);
461   evas_object_event_callback_del(events_overlay_, EVAS_CALLBACK_MOUSE_OUT,
462                                  OnMouseOut);
463   evas_object_event_callback_del(events_overlay_, EVAS_CALLBACK_MOUSE_WHEEL,
464                                  OnMouseWheel);
465 }
466
467 void EflEventHandler::AddTouchCallbacks() {
468   evas_object_event_callback_add(events_overlay_, EVAS_CALLBACK_MULTI_DOWN,
469                                  OnMultiTouchDownEvent, this);
470   evas_object_event_callback_add(events_overlay_, EVAS_CALLBACK_MULTI_MOVE,
471                                  OnMultiTouchMoveEvent, this);
472   evas_object_event_callback_add(events_overlay_, EVAS_CALLBACK_MULTI_UP,
473                                  OnMultiTouchUpEvent, this);
474 }
475
476 void EflEventHandler::DeleteTouchCallbacks() {
477   evas_object_event_callback_del(events_overlay_, EVAS_CALLBACK_MULTI_DOWN,
478                                  OnMultiTouchDownEvent);
479   evas_object_event_callback_del(events_overlay_, EVAS_CALLBACK_MULTI_MOVE,
480                                  OnMultiTouchMoveEvent);
481   evas_object_event_callback_del(events_overlay_, EVAS_CALLBACK_MULTI_UP,
482                                  OnMultiTouchUpEvent);
483 }
484
485 void EflEventHandler::AddKeyCallbacks() {
486   evas_object_event_callback_add(events_overlay_, EVAS_CALLBACK_KEY_DOWN,
487                                  OnKeyDown, this);
488   evas_object_event_callback_add(events_overlay_, EVAS_CALLBACK_KEY_UP, OnKeyUp,
489                                  this);
490 }
491
492 void EflEventHandler::DeleteKeyCallbacks() {
493   evas_object_event_callback_del(events_overlay_, EVAS_CALLBACK_KEY_DOWN,
494                                  OnKeyDown);
495   evas_object_event_callback_del(events_overlay_, EVAS_CALLBACK_KEY_UP,
496                                  OnKeyUp);
497 }
498
499 // static
500 void EflEventHandler::OnMouseDown(void* data,
501                                   Evas* evas,
502                                   Evas_Object* obj,
503                                   void* event_info) {
504   EflEventHandler* thiz = static_cast<EflEventHandler*>(data);
505   Evas_Event_Mouse_Down* ev = static_cast<Evas_Event_Mouse_Down*>(event_info);
506   LOG(INFO) << "OnMouseDown";
507
508   thiz->window_->UpdateFocus(true);
509
510   if (thiz->GetTouchEventsEnabled(ev)) {
511     thiz->ProcessTouchEvents(ev->timestamp, false);
512   } else {
513     MouseEvent event =
514         MakeWebMouseEvent(ET_MOUSE_PRESSED, ev, thiz->GetTopControlsHeight());
515     EflPlatformEventSource::GetInstance()->DispatchEflEvent(&event);
516   }
517 }
518
519 // static
520 void EflEventHandler::OnMouseUp(void* data,
521                                 Evas* evas,
522                                 Evas_Object* obj,
523                                 void* event_info) {
524   EflEventHandler* thiz = static_cast<EflEventHandler*>(data);
525   Evas_Event_Mouse_Up* ev = static_cast<Evas_Event_Mouse_Up*>(event_info);
526   LOG(INFO) << "OnMouseUp";
527
528   if (thiz->GetTouchEventsEnabled(ev)) {
529     thiz->ProcessTouchEvents(ev->timestamp, false);
530   } else {
531     MouseEvent event =
532         MakeWebMouseEvent(ET_MOUSE_RELEASED, ev, thiz->GetTopControlsHeight());
533     EflPlatformEventSource::GetInstance()->DispatchEflEvent(&event);
534   }
535 }
536
537 // static
538 void EflEventHandler::OnMouseMove(void* data,
539                                   Evas* evas,
540                                   Evas_Object* obj,
541                                   void* event_info) {
542   EflEventHandler* thiz = static_cast<EflEventHandler*>(data);
543
544   Evas_Event_Mouse_Move* ev = static_cast<Evas_Event_Mouse_Move*>(event_info);
545   if (thiz->GetTouchEventsEnabled(ev)) {
546     thiz->ProcessTouchEvents(ev->timestamp, false);
547   } else {
548     gfx::PointF location(ev->cur.canvas.x, ev->cur.canvas.y);
549     location.Offset(0, -thiz->GetTopControlsHeight());
550     int button = EvasToUIMouseButton(ev->buttons);
551     int event_flags = EvasModifiersToEventFlags(ev->modifiers);
552     event_flags |= button;
553     MouseEvent event(ET_MOUSE_MOVED, location, location, base::TimeTicks::Now(),
554                      event_flags, button);
555     const float sf = GetDeviceScaleFactor();
556     ui::MouseEvent::DispatcherApi(&event).set_movement(
557         gfx::Vector2dF((ev->cur.canvas.x / sf - ev->prev.canvas.x / sf),
558                        (ev->cur.canvas.y / sf - ev->prev.canvas.y / sf)));
559     EflPlatformEventSource::GetInstance()->DispatchEflEvent(&event);
560   }
561 }
562
563 // static
564 void EflEventHandler::OnMouseIn(void* data,
565                                 Evas* evas,
566                                 Evas_Object* obj,
567                                 void* event_info) {
568   EflEventHandler* thiz = static_cast<EflEventHandler*>(data);
569   thiz->window_->UpdateFocus(true);
570 }
571
572 // static
573 void EflEventHandler::OnMouseOut(void* data,
574                                  Evas* evas,
575                                  Evas_Object* obj,
576                                  void* event_info) {
577 #if !BUILDFLAG(IS_TIZEN)
578   EflEventHandler* thiz = static_cast<EflEventHandler*>(data);
579   thiz->window_->UpdateFocus(false);
580 #endif
581 }
582
583 // static
584 void EflEventHandler::OnMouseWheel(void* data,
585                                    Evas* evas,
586                                    Evas_Object* obj,
587                                    void* event_info) {
588   Evas_Event_Mouse_Wheel* ev = static_cast<Evas_Event_Mouse_Wheel*>(event_info);
589
590   gfx::Vector2d offset;
591   if (ev->direction)
592     offset.set_x(ev->z * kDefaultScrollStep);
593   else
594     offset.set_y(-(ev->z * kDefaultScrollStep));
595
596   gfx::PointF location(ev->canvas.x, ev->canvas.y);
597   int event_flags = EvasModifiersToEventFlags(ev->modifiers);
598   MouseWheelEvent event(offset, location, location, base::TimeTicks::Now(),
599                         event_flags, 0);
600   EflPlatformEventSource::GetInstance()->DispatchEflEvent(&event);
601 }
602
603 // static
604 void EflEventHandler::OnKeyDown(void* data,
605                                 Evas* evas,
606                                 Evas_Object* obj,
607                                 void* event_info) {
608   if (!obj || !event_info || !data)
609     return;
610
611   Evas_Event_Key_Down* key_down = static_cast<Evas_Event_Key_Down*>(event_info);
612   EflEventHandler* thiz = static_cast<EflEventHandler*>(data);
613   LOG(INFO) << "OnKeyDown, key : " << key_down->key;
614   LOG(INFO) << "Before consumed check (Key Name: " << key_down->key
615             << ", Key State: Down)";
616
617 #if BUILDFLAG(IS_TIZEN_TV)
618   if (!thiz->key_event_checker_.is_null() &&
619       !thiz->key_event_checker_.Run(event_info, true)) {
620     return;
621   }
622 #endif
623
624 #if BUILDFLAG(IS_TIZEN)
625   if (IsMobileProfile() || IsTvProfile()) {
626     if (thiz->FilterIMEKeyDownEvent(key_down)) {
627       LOG(INFO) << "OnKeyDown, IME filtered the key : " << key_down->key;
628       return;
629     }
630   }
631 #endif
632 #if BUILDFLAG(IS_TIZEN_TV)
633   if (IsTvProfile()) {
634     thiz->ConvertUpToReturnBackIfNeeded(key_down, true);
635
636     // In non webapp scene,"Cancel" key haven't added on the map,the keycode is
637     // 0. "Cancel" key is delivered by IME, for hiding IME panel,no need deliver
638     // the key event. Or else,the keycode 0 may exception handling by website.
639     if (!strcmp(key_down->key, "Cancel") && !blink::IsTIZENWRT())
640       return;
641   }
642 #endif
643
644   KeyEvent event = MakeWebKeyEvent(true, key_down);
645 #if BUILDFLAG(IS_TIZEN_TV)
646   // Needed for HBBTV single window, multiwebview scenario.
647   event.SetDispatcher(thiz->window());
648 #endif
649   auto im_context_efl = thiz->GetIMContextEfl();
650   if (!im_context_efl ||
651       im_context_efl->ShouldHandleImmediately(key_down->key)) {
652     EflPlatformEventSource::GetInstance()->DispatchEflEvent(&event);
653     return;
654   }
655
656   LOG(INFO) << "OnKeyUp,PushToKeyDownEventQueue,key:" << key_down->key;
657   im_context_efl->PushToKeyDownEventQueue(event);
658 }
659
660 // static
661 void EflEventHandler::OnKeyUp(void* data,
662                               Evas* evas,
663                               Evas_Object* obj,
664                               void* event_info) {
665   if (!obj || !event_info || !data)
666     return;
667
668   Evas_Event_Key_Up* key_up = static_cast<Evas_Event_Key_Up*>(event_info);
669   EflEventHandler* thiz = static_cast<EflEventHandler*>(data);
670   LOG(INFO) << "OnKeyUp, key : " << key_up->key;
671   LOG(INFO) << "Before consumed check (Key Name: " << key_up->key
672             << ", Key State: Up)";
673
674 #if BUILDFLAG(IS_TIZEN_TV)
675   if (!thiz->key_event_checker_.is_null() &&
676       !thiz->key_event_checker_.Run(event_info, false)) {
677     return;
678   }
679 #endif
680
681 #if BUILDFLAG(IS_TIZEN)
682   if (IsMobileProfile() || IsTvProfile()) {
683     if (thiz->FilterIMEKeyUpEvent(key_up)) {
684       LOG(INFO) << "OnKeyUp, IME filtered the key : " << key_up->key;
685       return;
686     }
687   }
688 #endif
689
690   if (IsTvProfile()) {
691 #if BUILDFLAG(IS_TIZEN_TV)
692     thiz->ConvertUpToReturnBackIfNeeded(key_up, false);
693 #endif
694
695     // For TV IME "Select" and "Cancel" key
696     if (thiz->im_context_efl_ && thiz->im_context_efl_->IsVisible()) {
697       if (!strcmp(key_up->key, "Select") || !strcmp(key_up->key, "Cancel"))
698         thiz->im_context_efl_->HidePanel();
699     }
700
701 #if BUILDFLAG(IS_TIZEN_TV)
702     // In non webapp scene,"Cancel" key haven't added on the map,the keycode is
703     // 0. "Cancel" key is delivered by IME, for hiding IME panel,no need deliver
704     // the key event. Or else,the keycode 0 may exception handling by website.
705     if (!strcmp(key_up->key, "Cancel") && !blink::IsTIZENWRT())
706       return;
707 #endif
708   }
709
710   KeyEvent event = MakeWebKeyEvent(false, key_up);
711 #if BUILDFLAG(IS_TIZEN_TV)
712   // Needed for HBBTV single window, multiwebview scenario.
713   event.SetDispatcher(thiz->window());
714 #endif
715   auto im_context_efl = thiz->GetIMContextEfl();
716   if (!im_context_efl || im_context_efl->ShouldHandleImmediately(key_up->key)) {
717     EflPlatformEventSource::GetInstance()->DispatchEflEvent(&event);
718     return;
719   }
720
721   LOG(INFO) << "OnKeyUp,PushToKeyUpEventQueue,key:" << key_up->key;
722   im_context_efl->PushToKeyUpEventQueue(event.key_code());
723 }
724
725 bool EflEventHandler::IsIMEHandleKeyEventEnabled() {
726   if (!GetIMContextEfl())
727     return false;
728
729 #if BUILDFLAG(IS_TIZEN_TV)
730   return GetIMContextEfl()->ImeHandleKeyEventEnabled();
731 #endif
732   return true;
733 }
734
735 bool EflEventHandler::FilterIMEKeyDownEvent(Evas_Event_Key_Down* key_down) {
736   if (!IsIMEHandleKeyEventEnabled())
737     return false;
738
739   bool was_filtered = false;
740   im_context_efl_->HandleKeyDownEvent(key_down, &was_filtered);
741
742   // It is for checking whether key is filtered or not about keyUp event.
743   // Because the process related with key is processed at
744   // EVAS_CALLBACK_KEY_DOWN although key is processed by Ecore_IMF, it isn't
745   // filtered by ecore_imf_context_filter_event about EVAS_CALLBACK_KEY_UP.
746   was_keydown_filtered_by_platform_ = was_filtered;
747
748   if (IsTvProfile() && !strcmp(key_down->key, "Return"))
749     was_return_keydown_filtered_by_platform_ = was_filtered;
750   if (was_filtered)
751     LOG(INFO) << "OnKeyDown,IME filtered the key:" << key_down->key;
752
753   return was_filtered;
754 }
755
756 bool EflEventHandler::FilterIMEKeyUpEvent(Evas_Event_Key_Up* key_up) {
757   if (!IsIMEHandleKeyEventEnabled())
758     return false;
759
760   // IME will change language mode when receive "Alt" keyup event.
761   // For avoiding IME change language when "Alt + Enter" scene,
762   // don't send the "Alt" keyup event when "Alt + Enter" keydown.
763   if (IsTvProfile() &&
764       (!strcmp(key_up->key, "Alt_L") || !strcmp(key_up->key, "Alt_R")) &&
765       was_alt_enter_key_down_) {
766     was_alt_enter_key_down_ = false;
767   } else {
768     bool was_filtered = false;
769     im_context_efl_->HandleKeyUpEvent(key_up, &was_filtered);
770   }
771
772   // Both selected key and retrun key events are emitted together
773   // while typing a single key on OSK by using remote controller.
774   // The redundant retrun key event needs to be ignored here.
775   if (IsTvProfile() && evas_device_name_get(key_up->dev)) {
776     if (!strstr(evas_device_name_get(key_up->dev), "ime") &&
777         im_context_efl_->IsVisible() && !strcmp(key_up->key, "Return")) {
778       return true;
779     }
780   }
781
782   // When IME was focused out in keydown event handler,
783   // 'was_filtered' will not give the right value.
784   // Refer to 'was_return_keydown_filtered_by_platform_' in this case.
785   if (IsTvProfile() && !strcmp(key_up->key, "Return") &&
786       was_return_keydown_filtered_by_platform_) {
787     was_return_keydown_filtered_by_platform_ = false;
788     return true;
789   }
790
791   if (was_keydown_filtered_by_platform_) {
792     was_keydown_filtered_by_platform_ = false;
793     return true;
794   }
795
796   return false;
797 }
798
799 void EflEventHandler::ConvertOriginToTarget(const EflWindow* new_target,
800                                             LocatedEvent* event) const {
801   gfx::Vector2d diff = window_->GetBoundsInDIP().origin() -
802                        new_target->GetBoundsInDIP().origin();
803   event->set_location_f(event->location_f() + diff);
804 }
805
806 // New requirement from tizen 6.5:
807 // press "up" key on the top of IME panel should handled as same behavior as
808 // press "Return Back" key on IME panel behavior:
809 // For WebBrowser, need hide IME panel and don't deliver the Return Back key
810 // event to WebBrowser; For WebApp, need hide IME panel and deliver the Return
811 // Back key event to WebApp.
812 #if BUILDFLAG(IS_TIZEN_TV)
813 template <typename EVT>
814 void EflEventHandler::ConvertUpToReturnBackIfNeeded(EVT* evt, bool is_press) {
815   if (!im_context_efl_ || !im_context_efl_->IsVisible() ||
816       strcmp(evt->key, "Up"))
817     return;
818
819   // No need hide IME panel when press the IME panel's up key.
820   Evas_Device_Class device_id = evas_device_class_get(evt->dev);
821   const char* device_name = evas_device_name_get(evt->dev);
822   if (device_id != EVAS_DEVICE_CLASS_KEYBOARD || !strcmp(device_name, "ime"))
823     return;
824
825   if (is_press) {
826     was_up_keypress_on_ime_top_ = true;
827   } else {
828     // make sure "press up key on the top of IME" scenes
829     if (!was_up_keypress_on_ime_top_)
830       return;
831
832     was_up_keypress_on_ime_top_ = false;
833   }
834
835   if (blink::IsWebBrowser() || blink::IsTIZENWRT()) {
836     evt->keyname = (char*)"Cancel"; /*Return Back key name*/
837     evt->key = (char*)"Cancel";     /*Return Back key*/
838     evt->string = (char*)"";        /*Return Back string*/
839     evt->keycode = 0;               /*Return Back keycode*/
840     LOG(INFO) << "Press Up key on the top of IME panel, handle the Up key as "
841                  "same as Return Back key!";
842   }
843 }
844
845 void EflEventHandler::SetKeyEventChecker(
846     const base::RepeatingCallback<bool(void*, bool)>& checker) {
847   key_event_checker_ = checker;
848 }
849 #endif
850
851 void EflEventHandler::OnMultiTouchDownEvent(void* data,
852                                             Evas* evas,
853                                             Evas_Object* obj,
854                                             void* event_info) {
855   EflEventHandler* thiz = static_cast<EflEventHandler*>(data);
856   thiz->ProcessTouchEvents(
857       static_cast<Evas_Event_Multi_Down*>(event_info)->timestamp, true);
858 }
859
860 void EflEventHandler::OnMultiTouchMoveEvent(void* data,
861                                             Evas* evas,
862                                             Evas_Object* obj,
863                                             void* event_info) {
864   EflEventHandler* thiz = static_cast<EflEventHandler*>(data);
865   thiz->ProcessTouchEvents(
866       static_cast<Evas_Event_Multi_Move*>(event_info)->timestamp, true);
867 }
868
869 void EflEventHandler::OnMultiTouchUpEvent(void* data,
870                                           Evas* evas,
871                                           Evas_Object* obj,
872                                           void* event_info) {
873   EflEventHandler* thiz = static_cast<EflEventHandler*>(data);
874   thiz->ProcessTouchEvents(
875       static_cast<Evas_Event_Multi_Up*>(event_info)->timestamp, true);
876 }
877
878 void EflEventHandler::ProcessTouchEvents(unsigned int timestamp,
879                                          bool is_multi_touch) {
880   unsigned count = evas_touch_point_list_count(window_->evas());
881   if (!count)
882     return;
883
884   int id;
885   Evas_Coord_Point pt;
886   Evas_Touch_Point_State state;
887   for (unsigned i = 0; i < count; ++i) {
888     id = evas_touch_point_list_nth_id_get(window_->evas(), i);
889     if ((id == 0 && is_multi_touch) || (id == 1 && !is_multi_touch))
890       continue;
891     evas_touch_point_list_nth_xy_get(window_->evas(), i, &pt.x, &pt.y);
892     state = evas_touch_point_list_nth_state_get(window_->evas(), i);
893     if (state == EVAS_TOUCH_POINT_STILL)
894       continue;
895
896     TouchEvent touch_event =
897         MakeTouchEvent(pt, state, id, timestamp, GetTopControlsHeight());
898     EflPlatformEventSource::GetInstance()->DispatchEflEvent(&touch_event);
899   }
900 }
901
902 }  // namespace ui