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