Upload initial version
[platform/core/uifw/libscl-ui-nui.git] / scl / scleventhandler.cpp
1 /*
2  * Copyright (c) 2012 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
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 #include "sclresourcecache.h"
19 #include "scleventhandler.h"
20 #include "scldebug.h"
21 #include "sclkeydefines.h"
22 #include "scluiimpl.h"
23
24 using namespace scl;
25
26 CSCLEventHandler::CSCLEventHandler()
27 {
28     SCL_DEBUG();
29
30     m_default_event_callback = NULL;
31     m_cur_input_mode_event_callback = NULL;
32 }
33
34 CSCLEventHandler::~CSCLEventHandler()
35 {
36     SCL_DEBUG();
37 }
38
39 CSCLEventHandler*
40 CSCLEventHandler::get_instance()
41 {
42     static CSCLEventHandler instance;
43     return &instance;
44 }
45
46 static void handle_shift_button_click_event(SclUIEventDesc ui_event_desc)
47 {
48     CSCLUIImpl *uiimpl = CSCLUIImpl::get_instance();
49     CSCLContext *context = CSCLContext::get_instance();
50
51     if (uiimpl && context) {
52         if (ui_event_desc.key_type == KEY_TYPE_CONTROL && ui_event_desc.key_event == MVK_Shift_L) {
53             switch (uiimpl->get_shift_state()) {
54                 case SCL_SHIFT_STATE_OFF: {
55                     uiimpl->set_shift_state(SCL_SHIFT_STATE_ON);
56                 }
57                 break;
58                 case SCL_SHIFT_STATE_ON: {
59                     /* The default next state should be LOCK state */
60                     SCLShiftState next_state = SCL_SHIFT_STATE_LOCK;
61                     if (context->get_shift_multi_touch_enabled()) {
62                         if (context) {
63                             if (context->get_shift_multi_touch_state() == SCL_SHIFT_MULTITOUCH_ON_PRESSED) {
64                                 /* If the shift multi touch state is ON_PRESSED, don't leave ON state now */
65                                 next_state = SCL_SHIFT_STATE_ON;
66                             } else if (context->get_shift_multi_touch_state() == SCL_SHIFT_MULTITOUCH_ON_KEY_ENTERED) {
67                                 /* If some keys were already entered while shift key was in pressed state, move to OFF */
68                                 next_state = SCL_SHIFT_STATE_OFF;
69                             }
70                         }
71                     }
72                     uiimpl->set_shift_state(next_state);
73                 }
74                 break;
75                 case SCL_SHIFT_STATE_LOCK: {
76                     uiimpl->set_shift_state(SCL_SHIFT_STATE_OFF);
77                 }
78                 break;
79                 case SCL_SHIFT_STATE_MAX:
80                 default:
81                     break;
82             }
83         }
84     }
85 }
86
87 static void handle_shift_state_on_button_click_event(SclUIEventDesc ui_event_desc)
88 {
89     CSCLUIImpl *uiimpl = CSCLUIImpl::get_instance();
90
91     /* do not need the libscl-ui auto-captial the shift state  */
92     if (FALSE == uiimpl->get_autocapital_shift_state()) {
93         return;
94     }
95
96     CSCLContext *context = CSCLContext::get_instance();
97
98     sclboolean turn_shift_off = TRUE;
99     if (ui_event_desc.key_event == MVK_Shift_L || ui_event_desc.key_event == MVK_Caps_Lock) {
100         turn_shift_off = FALSE;
101     }
102     if (ui_event_desc.key_type == KEY_TYPE_MODECHANGE) {
103         turn_shift_off = FALSE;
104     }
105     if (ui_event_desc.key_modifier == KEY_MODIFIER_MULTITAP_START ||
106         ui_event_desc.key_modifier == KEY_MODIFIER_MULTITAP_REPEAT) {
107         turn_shift_off = FALSE;
108     }
109     /* If we are in ON_PRESSED or ON_KEY_ENTERED mode of shift multi touch state, do not turn it off now */
110     if (context) {
111         if (context->get_shift_multi_touch_enabled() && turn_shift_off) {
112             if (context->get_shift_multi_touch_state() == SCL_SHIFT_MULTITOUCH_ON_PRESSED) {
113                 context->set_shift_multi_touch_state(SCL_SHIFT_MULTITOUCH_ON_KEY_ENTERED);
114                 turn_shift_off = FALSE;
115             } else if (context->get_shift_multi_touch_state() == SCL_SHIFT_MULTITOUCH_ON_KEY_ENTERED) {
116                 turn_shift_off = FALSE;
117             }
118         }
119     }
120     if (turn_shift_off) {
121         if (uiimpl->get_shift_state() == SCL_SHIFT_STATE_ON) {
122             uiimpl->set_shift_state(SCL_SHIFT_STATE_OFF);
123         }
124     }
125 }
126
127 static void handle_mode_change_button_click_event(SclUIEventDesc ui_event_desc)
128 {
129     CSCLUIImpl *uiimpl = CSCLUIImpl::get_instance();
130
131     if (uiimpl) {
132         if (ui_event_desc.key_type == KEY_TYPE_MODECHANGE) {
133             uiimpl->set_input_mode(ui_event_desc.key_value);
134         }
135     }
136 }
137
138 SCLEventReturnType
139 CSCLEventHandler::on_event_key_clicked(SclUIEventDesc ui_event_desc)
140 {
141     SCLEventReturnType ret = SCL_EVENT_PASS_ON;
142
143     pre_process_ui_event(ui_event_desc);
144
145     if (m_cur_input_mode_event_callback) {
146         ret = m_cur_input_mode_event_callback->on_event_key_clicked(ui_event_desc);
147     }
148     if (ret == SCL_EVENT_PASS_ON) {
149         if (m_default_event_callback) {
150             ret = m_default_event_callback->on_event_key_clicked(ui_event_desc);
151         }
152     }
153
154     if (ret == SCL_EVENT_PASS_ON) {
155         /* Here we can put the fallback processing of this UIEvent */
156
157         /* General requirement - 1 */
158         /* When the SHIFT button was clicked, we change the shift state to OFF -> ON -> LOCK -> OFF ... */
159         handle_shift_button_click_event(ui_event_desc);
160
161         /* General requirement - 2 */
162         /* If a key was clicked but it is neither a SHIFT nor a CAPSLOCK, we just turn the shift off, if it is on */
163         handle_shift_state_on_button_click_event(ui_event_desc);
164
165         /* General requirement - 3 */
166         /* If the key type is KEY_TYPE_MODECHANGE, change the current input mode to given key_value */
167         handle_mode_change_button_click_event(ui_event_desc);
168     }
169
170     return ret;
171 }
172
173 SCLEventReturnType
174 CSCLEventHandler::on_event_drag_state_changed(SclUIEventDesc ui_event_desc)
175 {
176     SCLEventReturnType ret = SCL_EVENT_PASS_ON;
177
178     pre_process_ui_event(ui_event_desc);
179
180     if (m_cur_input_mode_event_callback) {
181         ret = m_cur_input_mode_event_callback->on_event_drag_state_changed(ui_event_desc);
182     }
183     if (ret == SCL_EVENT_PASS_ON) {
184         if (m_default_event_callback) {
185             ret = m_default_event_callback->on_event_drag_state_changed(ui_event_desc);
186         }
187     }
188
189     if (ret == SCL_EVENT_PASS_ON) {
190         /* Here we can put the fallback processing of this UIEvent */
191         CSCLUIImpl *uiimpl = CSCLUIImpl::get_instance();
192         CSCLContext *context = CSCLContext::get_instance();
193
194         /* General requirement - 1 */
195         /* When the SHIFT button was 'pressed' and shift button multitouch action is enabled,
196            we change the current shift multitouch state to 'ON_PRESSED' */
197         if (uiimpl && context) {
198             if (context->get_shift_multi_touch_enabled()) {
199                 if (ui_event_desc.event_type == EVENT_TYPE_PRESS) {
200                     if (context) {
201                         if (ui_event_desc.key_event == MVK_Shift_L) {
202                             if (context->get_shift_multi_touch_state() == SCL_SHIFT_MULTITOUCH_OFF) {
203                                 uiimpl->set_shift_state(SCL_SHIFT_STATE_ON);
204                                 context->set_shift_multi_touch_state(SCL_SHIFT_MULTITOUCH_ON_PRESSED);
205                             }
206                         }
207                     }
208                 }
209             }
210         }
211     }
212
213     return ret;
214 }
215
216 SCLEventReturnType
217 CSCLEventHandler::on_event_notification(SCLUINotiType noti_type, SclNotiDesc *etc_info)
218 {
219     SCLEventReturnType ret = SCL_EVENT_PASS_ON;
220
221     if (m_cur_input_mode_event_callback) {
222         ret = m_cur_input_mode_event_callback->on_event_notification(noti_type, etc_info);
223     }
224     if (ret == SCL_EVENT_PASS_ON) {
225         if (m_default_event_callback) {
226             ret = m_default_event_callback->on_event_notification(noti_type, etc_info);
227         }
228     }
229
230     if (ret == SCL_EVENT_PASS_ON) {
231         /* Here we can put the fallback processing of this UIEvent */
232     }
233
234     return ret;
235 }
236
237 sclboolean
238 CSCLEventHandler::set_input_mode(const sclchar *input_mode)
239 {
240     SCL_DEBUG();
241
242     sclboolean ret = FALSE;
243     SclNotiInputModeChangeDesc desc;
244     desc.input_mode = input_mode;
245     if (SCL_EVENT_PASS_ON == on_event_notification(SCL_UINOTITYPE_INPUT_MODE_CHANGE, &desc)) {
246         m_cur_input_mode_event_callback = NULL;
247
248         if (input_mode) {
249             std::string id = input_mode;
250             std::map<std::string, ISCLUIEventCallback*>::iterator iter = m_input_mode_event_callbacks.find(input_mode);
251             if (iter != m_input_mode_event_callbacks.end()) {
252                 m_cur_input_mode_event_callback = (iter->second);
253             }
254         }
255
256         ret = TRUE;
257     }
258
259     return ret;
260 }
261
262 void
263 CSCLEventHandler::set_event_callback(ISCLUIEventCallback *callback, const sclchar *input_mode)
264 {
265     SCL_DEBUG();
266
267     scl_assert_return(callback);
268
269     if (input_mode) {
270         std::string id = input_mode;
271         m_input_mode_event_callbacks[id] = callback;
272     } else {
273         m_default_event_callback = callback;
274     }
275 }
276
277 void
278 CSCLEventHandler::pre_process_ui_event(SclUIEventDesc &ui_event_desc)
279 {
280     SCL_DEBUG();
281
282     typedef struct {
283         const sclchar *key_value;
284         sclulong key_event;
285     } KEY_VALUE_EVENT_CONVERT_TABLE;
286
287     KEY_VALUE_EVENT_CONVERT_TABLE control_keys[] = {
288         {"Space",       MVK_space       },
289         {"BackSpace",   MVK_BackSpace   },
290         {"Shift",       MVK_Shift_L     },
291         {"CapsLock",    MVK_Caps_Lock   },
292         {"Enter",       MVK_Return      },
293         {"Left",        MVK_Left        },
294         {"Right",       MVK_Right       },
295         {"Up",          MVK_Up          },
296         {"Down",        MVK_Down        },
297         {"Escape",      MVK_Escape      },
298     };
299
300     /* Translate key_values only when key_event is 0 and key_value is not NULL */
301     if (ui_event_desc.key_value && ui_event_desc.key_event == 0) {
302         if (ui_event_desc.key_type == KEY_TYPE_CHAR) {
303             /* If the key_value is a string with length 1, and the first character has value between
304                SCL_ISCHAR range, provide the corresponding ASCII code in key_event field */
305             if (ui_event_desc.key_value[0] != '\0' && ui_event_desc.key_value[1] == '\0') {
306                 if (SCL_ISCHAR(ui_event_desc.key_value[0])) {
307                     ui_event_desc.key_event = static_cast<sclulong>(ui_event_desc.key_value[0]);
308                 }
309             }
310         } else if (ui_event_desc.key_type == KEY_TYPE_CONTROL) {
311             const scluint control_keys_size = sizeof(control_keys) / sizeof(KEY_VALUE_EVENT_CONVERT_TABLE);
312
313             for (scluint loop = 0;loop < control_keys_size;loop++) {
314                 if (strncmp(control_keys[loop].key_value, ui_event_desc.key_value, strlen(control_keys[loop].key_value)) == 0) {
315                     ui_event_desc.key_event = control_keys[loop].key_event;
316                 }
317             }
318         } else if (ui_event_desc.key_type == KEY_TYPE_STRING) {
319             CSCLResourceCache *cache = CSCLResourceCache::get_instance();
320             if (cache) {
321                 ui_event_desc.key_value = cache->find_substituted_string(ui_event_desc.key_value);
322             }
323         }
324     }
325 }