[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / focus-manager / keyinput-focus-manager-impl.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include "keyinput-focus-manager-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali-toolkit/public-api/controls/control-impl.h>
23 #include <dali/integration-api/adaptor-framework/adaptor.h>
24 #include <dali/integration-api/adaptor-framework/scene-holder.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/devel-api/adaptor-framework/window-devel.h>
27 #include <dali/public-api/actors/layer.h>
28 #include <cstring> // for strcmp
29
30 // INTERNAL INCLUDES
31 #include <dali-toolkit/devel-api/controls/control-devel.h>
32 namespace Dali
33 {
34 namespace Toolkit
35 {
36 namespace Internal
37 {
38 namespace
39 {
40 // Signals
41
42 const char* const SIGNAL_KEY_INPUT_FOCUS_CHANGED = "keyInputFocusChanged";
43
44 } // namespace
45
46 KeyInputFocusManager::KeyInputFocusManager()
47 : mSlotDelegate(this),
48   mCurrentFocusControl(),
49   mCurrentWindowId(0)
50 {
51   // Retrieve all the existing widnows
52   Dali::SceneHolderList sceneHolders = Adaptor::Get().GetSceneHolders();
53   for(auto iter = sceneHolders.begin(); iter != sceneHolders.end(); ++iter)
54   {
55     (*iter).KeyEventGeneratedSignal().Connect(mSlotDelegate, &KeyInputFocusManager::OnKeyEvent);
56   }
57
58   // Get notified when any new scene holder is created afterwards
59   Adaptor::Get().WindowCreatedSignal().Connect(mSlotDelegate, &KeyInputFocusManager::OnSceneHolderCreated);
60 }
61
62 KeyInputFocusManager::~KeyInputFocusManager()
63 {
64 }
65
66 void KeyInputFocusManager::OnSceneHolderCreated(Dali::Integration::SceneHolder& sceneHolder)
67 {
68   sceneHolder.KeyEventGeneratedSignal().Connect(mSlotDelegate, &KeyInputFocusManager::OnKeyEvent);
69 }
70
71 void KeyInputFocusManager::SetFocus(Toolkit::Control control)
72 {
73   if(!control)
74   {
75     // No-op
76     return;
77   }
78
79   if(control == mCurrentFocusControl)
80   {
81     // Control already has focus
82     return;
83   }
84
85   control.OffSceneSignal().Connect(mSlotDelegate, &KeyInputFocusManager::OnFocusControlSceneDisconnection);
86
87   Dali::Toolkit::Control previousFocusControl = GetCurrentFocusControl();
88
89   // Set control to currentFocusControl
90   mCurrentFocusControl = control;
91   mCurrentWindowId = static_cast<uint32_t>(Integration::SceneHolder::Get(control).GetNativeId());
92
93   if(previousFocusControl)
94   {
95     // Notify the control that it has lost key input focus
96     GetImplementation(previousFocusControl).OnKeyInputFocusLost();
97   }
98
99   // Tell the new actor that it has gained focus.
100   GetImplementation(control).OnKeyInputFocusGained();
101
102   // Emit the signal to inform focus change to the application.
103   if(!mKeyInputFocusChangedSignal.Empty())
104   {
105     mKeyInputFocusChangedSignal.Emit(control, previousFocusControl);
106   }
107 }
108
109 void KeyInputFocusManager::RemoveFocus(Toolkit::Control control)
110 {
111   if(control && control == mCurrentFocusControl)
112   {
113     DALI_LOG_RELEASE_INFO("RemoveFocus id:(%d)\n", control.GetProperty<int32_t>(Dali::Actor::Property::ID));
114     control.OffSceneSignal().Disconnect(mSlotDelegate, &KeyInputFocusManager::OnFocusControlSceneDisconnection);
115
116     mCurrentFocusControl.Reset();
117     mCurrentWindowId = 0;
118
119     // Notify the control that it has lost key input focus
120     GetImplementation(control).OnKeyInputFocusLost();
121   }
122 }
123
124 Toolkit::Control KeyInputFocusManager::GetCurrentFocusControl() const
125 {
126   return mCurrentFocusControl;
127 }
128
129 uint32_t KeyInputFocusManager::GetCurrentWindowId() const
130 {
131   return mCurrentWindowId;
132 }
133
134 Toolkit::KeyInputFocusManager::KeyInputFocusChangedSignalType& KeyInputFocusManager::KeyInputFocusChangedSignal()
135 {
136   return mKeyInputFocusChangedSignal;
137 }
138
139 bool KeyInputFocusManager::OnKeyEvent(const KeyEvent& event)
140 {
141   bool consumed = false;
142
143   Toolkit::Control control = GetCurrentFocusControl();
144   if(control)
145   {
146     // Key events that occur in windows other than the currently focused control are skipped.
147     uint32_t eventWindowId = event.GetWindowId();
148     if(eventWindowId > 0 && GetCurrentWindowId() != eventWindowId)
149     {
150       DALI_LOG_RELEASE_INFO("Current control window id %d, window ID where key event occurred %d : key event skip\n", GetCurrentWindowId(), eventWindowId);
151       return consumed;
152     }
153
154     Dali::Actor dispatch = control;
155     while(dispatch)
156     {
157       // If the DISPATCH_KEY_EVENTS is false, it cannot emit key event.
158       Toolkit::Control dispatchControl = Toolkit::Control::DownCast(dispatch);
159       if(dispatchControl && !dispatchControl.GetProperty<bool>(Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS))
160       {
161         return true;
162       }
163       dispatch = dispatch.GetParent();
164     }
165
166     // Notify the control about the key event
167     consumed = EmitKeyEventSignal(control, event);
168   }
169
170   return consumed;
171 }
172
173 bool KeyInputFocusManager::EmitKeyEventSignal(Toolkit::Control control, const KeyEvent& event)
174 {
175   bool consumed = false;
176
177   if(control)
178   {
179     consumed = GetImplementation(control).EmitKeyEventSignal(event);
180
181     // if control doesn't consume KeyEvent, give KeyEvent to its parent.
182     if(!consumed)
183     {
184       Toolkit::Control parent = Toolkit::Control::DownCast(control.GetParent());
185
186       if(parent)
187       {
188         consumed = EmitKeyEventSignal(parent, event);
189       }
190     }
191   }
192
193   return consumed;
194 }
195
196 void KeyInputFocusManager::OnFocusControlSceneDisconnection(Dali::Actor actor)
197 {
198   RemoveFocus(Dali::Toolkit::Control::DownCast(actor));
199 }
200
201 bool KeyInputFocusManager::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
202 {
203   bool                  connected(true);
204   KeyInputFocusManager* manager = dynamic_cast<KeyInputFocusManager*>(object);
205
206   if(manager)
207   {
208     if(0 == strcmp(signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_CHANGED))
209     {
210       manager->KeyInputFocusChangedSignal().Connect(tracker, functor);
211     }
212     else
213     {
214       // signalName does not match any signal
215       connected = false;
216     }
217   }
218
219   return connected;
220 }
221
222 } // namespace Internal
223
224 } // namespace Toolkit
225
226 } // namespace Dali