2 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/window-system/common/event-handler.h>
25 #include <dali/public-api/events/touch-point.h>
26 #include <dali/public-api/events/key-event.h>
27 #include <dali/public-api/events/wheel-event.h>
28 #include <dali/integration-api/debug.h>
29 #include <dali/integration-api/events/key-event-integ.h>
30 #include <dali/integration-api/events/touch-event-integ.h>
31 #include <dali/integration-api/events/hover-event-integ.h>
32 #include <dali/integration-api/events/wheel-event-integ.h>
33 #include <dali/integration-api/scene.h>
36 #include <dali/internal/input/common/gesture-manager.h>
37 #include <dali/internal/clipboard/common/clipboard-impl.h>
38 #include <dali/internal/input/common/key-impl.h>
39 #include <dali/internal/input/common/physical-keyboard-impl.h>
40 #include <dali/internal/styling/common/style-monitor-impl.h>
41 #include <dali/internal/window-system/common/window-render-surface.h>
52 #if defined(DEBUG_ENABLED)
55 Integration::Log::Filter* gTouchEventLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_TOUCH");
56 Integration::Log::Filter* gSelectionEventLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_SELECTION");
57 } // unnamed namespace
63 // Copied from x server
64 static unsigned int GetCurrentMilliSeconds(void)
69 static clockid_t clockid;
73 #ifdef CLOCK_MONOTONIC_COARSE
74 if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
75 (tp.tv_nsec / 1000) <= 1000 && clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
77 clockid = CLOCK_MONOTONIC_COARSE;
81 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
83 clockid = CLOCK_MONOTONIC;
90 if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
92 return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
95 gettimeofday(&tv, NULL);
96 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
99 } // unnamed namespace
101 EventHandler::EventHandler( Dali::Integration::Scene scene, CoreEventInterface& coreEventInterface, GestureManager& gestureManager, DamageObserver& damageObserver )
103 mCoreEventInterface( coreEventInterface ),
104 mGestureManager( gestureManager ),
105 mStyleMonitor( StyleMonitor::Get() ),
106 mDamageObserver( damageObserver ),
107 mRotationObserver( NULL ),
108 mAccessibilityAdaptor( AccessibilityAdaptor::Get() ),
109 mClipboardEventNotifier( ClipboardEventNotifier::Get() ),
110 mClipboard( Clipboard::Get() ),
116 // this code only works with the WindowRenderSurface so need to downcast
117 WindowRenderSurface* windowRenderSurface = static_cast< WindowRenderSurface* >( scene.GetSurface() );
118 if( windowRenderSurface )
120 WindowBase* windowBase = windowRenderSurface->GetWindowBase();
123 windowBase->FocusChangedSignal().Connect( this, &EventHandler::OnFocusChanged );
124 windowBase->WindowDamagedSignal().Connect( this, &EventHandler::OnWindowDamaged );
125 windowBase->RotationSignal().Connect( this, &EventHandler::SendRotationPrepareEvent );
126 windowBase->TouchEventSignal().Connect( this, &EventHandler::OnTouchEvent );
127 windowBase->WheelEventSignal().Connect( this, &EventHandler::OnWheelEvent );
128 windowBase->KeyEventSignal().Connect( this, &EventHandler::OnKeyEvent );
129 windowBase->SelectionDataSendSignal().Connect( this, &EventHandler::OnSelectionDataSend );
130 windowBase->SelectionDataReceivedSignal().Connect( this, &EventHandler::OnSelectionDataReceived );
131 windowBase->StyleChangedSignal().Connect( this, &EventHandler::OnStyleChanged );
132 windowBase->AccessibilitySignal().Connect( this, &EventHandler::OnAccessibilityNotification );
136 EventHandler::~EventHandler()
138 mGestureManager.Stop();
141 void EventHandler::SendEvent( Integration::Point& point, unsigned long timeStamp )
145 timeStamp = GetCurrentMilliSeconds();
148 ConvertTouchPosition( point );
150 Integration::TouchEvent touchEvent;
151 Integration::HoverEvent hoverEvent;
152 Integration::TouchEventCombiner::EventDispatchType type = mCombiner.GetNextTouchEvent(point, timeStamp, touchEvent, hoverEvent);
153 if( type != Integration::TouchEventCombiner::DispatchNone )
155 DALI_LOG_INFO( gTouchEventLogFilter, Debug::General, "%d: Device %d: Button state %d (%.2f, %.2f)\n", timeStamp, point.GetDeviceId(), point.GetState(), point.GetScreenPosition().x, point.GetScreenPosition().y );
156 // First the touch and/or hover event & related gesture events are queued
157 if( type == Integration::TouchEventCombiner::DispatchTouch || type == Integration::TouchEventCombiner::DispatchBoth )
159 mScene.QueueEvent( touchEvent );
160 mGestureManager.SendEvent( mScene, touchEvent );
163 if( type == Integration::TouchEventCombiner::DispatchHover || type == Integration::TouchEventCombiner::DispatchBoth )
165 mScene.QueueEvent( hoverEvent );
168 // Next the events are processed with a single call into Core
169 mCoreEventInterface.ProcessCoreEvents();
173 void EventHandler::SendEvent(Integration::KeyEvent& keyEvent)
175 Dali::PhysicalKeyboard physicalKeyboard = PhysicalKeyboard::Get();
176 if( physicalKeyboard )
178 if( ! KeyLookup::IsDeviceButton( keyEvent.keyName.c_str() ) )
180 GetImplementation( physicalKeyboard ).KeyReceived( keyEvent.time > 1 );
184 // Create send KeyEvent to Core.
185 mScene.QueueEvent( keyEvent );
186 mCoreEventInterface.ProcessCoreEvents();
189 void EventHandler::SendWheelEvent( WheelEvent& wheelEvent )
191 // Create WheelEvent and send to Core.
192 Integration::WheelEvent event( static_cast< Integration::WheelEvent::Type >(wheelEvent.type), wheelEvent.direction, wheelEvent.modifiers, wheelEvent.point, wheelEvent.z, wheelEvent.timeStamp );
194 mScene.QueueEvent( event );
195 mCoreEventInterface.ProcessCoreEvents();
198 void EventHandler::SendEvent( StyleChange::Type styleChange )
200 DALI_ASSERT_DEBUG( mStyleMonitor && "StyleMonitor Not Available" );
201 GetImplementation( mStyleMonitor ).StyleChanged(styleChange);
204 void EventHandler::SendEvent( const DamageArea& area )
206 mDamageObserver.OnDamaged( area );
209 void EventHandler::SendRotationPrepareEvent( const RotationEvent& event )
211 if( mRotationObserver != NULL )
213 mRotationAngle = event.angle;
214 mWindowWidth = event.width;
215 mWindowHeight = event.height;
217 mRotationObserver->OnRotationPrepare( event );
218 mRotationObserver->OnRotationRequest();
222 void EventHandler::SendRotationRequestEvent( )
224 // No need to separate event into prepare and request
227 void EventHandler::FeedTouchPoint( TouchPoint& point, int timeStamp)
229 Integration::Point convertedPoint( point );
230 SendEvent( convertedPoint, timeStamp );
233 void EventHandler::FeedWheelEvent( WheelEvent& wheelEvent )
235 SendWheelEvent( wheelEvent );
238 void EventHandler::FeedKeyEvent( KeyEvent& event )
240 Integration::KeyEvent convertedEvent( event );
241 SendEvent( convertedEvent );
244 void EventHandler::FeedEvent( Integration::Event& event )
246 mScene.QueueEvent( event );
247 mCoreEventInterface.ProcessCoreEvents();
250 void EventHandler::Reset()
254 // Any touch listeners should be told of the interruption.
255 Integration::TouchEvent event;
256 Integration::Point point;
257 point.SetState( PointState::INTERRUPTED );
258 event.AddPoint( point );
260 // First the touch event & related gesture events are queued
261 mScene.QueueEvent( event );
263 mGestureManager.SendEvent( mScene, event );
265 // Next the events are processed with a single call into Core
266 mCoreEventInterface.ProcessCoreEvents();
269 void EventHandler::Pause()
275 void EventHandler::Resume()
281 void EventHandler::SetRotationObserver( RotationObserver* observer )
283 mRotationObserver = observer;
286 void EventHandler::OnTouchEvent( Integration::Point& point, unsigned long timeStamp )
288 SendEvent( point, timeStamp );
291 void EventHandler::OnWheelEvent( WheelEvent& wheelEvent )
293 SendWheelEvent( wheelEvent );
296 void EventHandler::OnKeyEvent( Integration::KeyEvent& keyEvent )
298 SendEvent( keyEvent );
301 void EventHandler::OnFocusChanged( bool focusIn )
303 // If the window gains focus and we hid the keyboard then show it again.
306 Dali::Clipboard clipboard = Clipboard::Get();
309 clipboard.HideClipboard();
314 // Hiding clipboard event will be ignored once because window focus out event is always received on showing clipboard
315 Dali::Clipboard clipboard = Clipboard::Get();
318 Clipboard& clipBoardImpl( GetImplementation( clipboard ) );
319 clipBoardImpl.HideClipboard(true);
324 void EventHandler::OnWindowDamaged( const DamageArea& area )
329 void EventHandler::OnSelectionDataSend( void* event )
331 Dali::Clipboard clipboard = Clipboard::Get();
334 Clipboard& clipBoardImpl( GetImplementation( clipboard ) );
335 clipBoardImpl.ExcuteBuffered( true, event );
339 void EventHandler::OnSelectionDataReceived( void* event )
341 // We have got the selected content, inform the clipboard event listener (if we have one).
342 Dali::Clipboard clipboard = Clipboard::Get();
343 char* selectionData = NULL;
346 Clipboard& clipBoardImpl( GetImplementation( clipboard ) );
347 selectionData = clipBoardImpl.ExcuteBuffered( false, event );
350 if( selectionData && mClipboardEventNotifier )
352 ClipboardEventNotifier& clipboardEventNotifier( ClipboardEventNotifier::GetImplementation( mClipboardEventNotifier ) );
353 std::string content( selectionData, strlen( selectionData ) );
355 clipboardEventNotifier.SetContent( content );
356 clipboardEventNotifier.EmitContentSelectedSignal();
358 DALI_LOG_INFO( gSelectionEventLogFilter, Debug::General, "EcoreEventSelectionNotify: Content(%d): %s\n" , strlen(selectionData), selectionData );
362 void EventHandler::OnStyleChanged( StyleChange::Type styleChange )
364 SendEvent( styleChange );
367 void EventHandler::OnAccessibilityNotification( const WindowBase::AccessibilityInfo& info )
369 #ifdef DALI_ELDBUS_AVAILABLE
375 if( !mAccessibilityAdaptor )
377 DALI_LOG_ERROR( "Invalid accessibility adaptor\n" );
381 AccessibilityAdaptor* accessibilityAdaptor( &AccessibilityAdaptor::GetImplementation( mAccessibilityAdaptor ) );
382 if( !accessibilityAdaptor )
384 DALI_LOG_ERROR( "Cannot access accessibility adaptor\n" );
388 // Create a touch point object.
389 TouchPoint::State touchPointState( TouchPoint::Down );
390 if( info.state == 0 )
392 touchPointState = TouchPoint::Down; // Mouse down.
394 else if( info.state == 1 )
396 touchPointState = TouchPoint::Motion; // Mouse move.
398 else if( info.state == 2 )
400 touchPointState = TouchPoint::Up; // Mouse up.
404 touchPointState = TouchPoint::Interrupted; // Error.
407 // Send touch event to accessibility adaptor.
408 TouchPoint point( 0, touchPointState, static_cast< float >( info.startX ), static_cast< float >( info.startY ) );
410 // Perform actions based on received gestures.
411 // Note: This is seperated from the reading so we can have other input readers without changing the below code.
412 switch( info.gestureValue )
414 case 0: // OneFingerHover
417 accessibilityAdaptor->HandleActionReadEvent( static_cast< unsigned int >( info.startX ), static_cast< unsigned int >( info.startY ), true /* allow read again */ );
420 case 1: // TwoFingersHover
422 // In accessibility mode, scroll action should be handled when the currently focused actor is contained in scrollable control
423 accessibilityAdaptor->HandleActionScrollEvent( point, GetCurrentMilliSeconds() );
426 case 2: // ThreeFingersHover
428 // Read from top item on screen continuously.
429 accessibilityAdaptor->HandleActionReadFromTopEvent();
432 case 3: // OneFingerFlickLeft
434 // Move to previous item.
435 accessibilityAdaptor->HandleActionReadPreviousEvent();
438 case 4: // OneFingerFlickRight
440 // Move to next item.
441 accessibilityAdaptor->HandleActionReadNextEvent();
444 case 5: // OneFingerFlickUp
446 // Move to previous item.
447 accessibilityAdaptor->HandleActionPreviousEvent();
450 case 6: // OneFingerFlickDown
452 // Move to next item.
453 accessibilityAdaptor->HandleActionNextEvent();
456 case 7: // TwoFingersFlickUp
458 // Scroll up the list.
459 accessibilityAdaptor->HandleActionScrollUpEvent();
462 case 8: // TwoFingersFlickDown
464 // Scroll down the list.
465 accessibilityAdaptor->HandleActionScrollDownEvent();
468 case 9: // TwoFingersFlickLeft
470 // Scroll left to the previous page
471 accessibilityAdaptor->HandleActionPageLeftEvent();
474 case 10: // TwoFingersFlickRight
476 // Scroll right to the next page
477 accessibilityAdaptor->HandleActionPageRightEvent();
480 case 11: // ThreeFingersFlickLeft
485 case 12: // ThreeFingersFlickRight
490 case 13: // ThreeFingersFlickUp
495 case 14: // ThreeFingersFlickDown
500 case 15: // OneFingerSingleTap
503 accessibilityAdaptor->HandleActionReadEvent( static_cast< unsigned int >( info.startX ), static_cast< unsigned int >( info.startY ), true /* allow read again */ );
506 case 16: // OneFingerDoubleTap
508 // Activate selected item / active edit mode.
509 accessibilityAdaptor->HandleActionActivateEvent();
512 case 17: // OneFingerTripleTap
515 accessibilityAdaptor->HandleActionZoomEvent();
518 case 18: // TwoFingersSingleTap
520 // Pause/Resume current speech
521 accessibilityAdaptor->HandleActionReadPauseResumeEvent();
524 case 19: // TwoFingersDoubleTap
526 // Start/Stop current action
527 accessibilityAdaptor->HandleActionStartStopEvent();
530 case 20: // TwoFingersTripleTap
532 // Read information from indicator
536 case 21: // ThreeFingersSingleTap
538 // Read from top item on screen continuously.
539 accessibilityAdaptor->HandleActionReadFromTopEvent();
542 case 22: // ThreeFingersDoubleTap
544 // Read from next item continuously.
545 accessibilityAdaptor->HandleActionReadFromNextEvent();
548 case 23: // ThreeFingersTripleTap
553 case 24: // OneFingerFlickLeftReturn
555 // Scroll up to the previous page
556 accessibilityAdaptor->HandleActionPageUpEvent();
559 case 25: // OneFingerFlickRightReturn
561 // Scroll down to the next page
562 accessibilityAdaptor->HandleActionPageDownEvent();
565 case 26: // OneFingerFlickUpReturn
567 // Move to the first item on screen
568 accessibilityAdaptor->HandleActionMoveToFirstEvent();
571 case 27: // OneFingerFlickDownReturn
573 // Move to the last item on screen
574 accessibilityAdaptor->HandleActionMoveToLastEvent();
577 case 28: // TwoFingersFlickLeftReturn
582 case 29: // TwoFingersFlickRightReturn
587 case 30: // TwoFingersFlickUpReturn
592 case 31: // TwoFingersFlickDownReturn
597 case 32: // ThreeFingersFlickLeftReturn
602 case 33: // ThreeFingersFlickRightReturn
607 case 34: // ThreeFingersFlickUpReturn
612 case 35: // ThreeFingersFlickDownReturn
621 void EventHandler::ConvertTouchPosition( Integration::Point& point )
623 Vector2 position = point.GetScreenPosition();
624 Vector2 convertedPosition;
626 switch( mRotationAngle )
630 convertedPosition.x = mWindowWidth - position.y;
631 convertedPosition.y = position.x;
636 convertedPosition.x = mWindowWidth - position.x;
637 convertedPosition.y = mWindowHeight - position.y;
642 convertedPosition.x = position.y;
643 convertedPosition.y = mWindowHeight - position.x;
648 convertedPosition = position;
653 point.SetScreenPosition( convertedPosition );
656 } // namespace Adaptor
658 } // namespace Internal