IME rotation sync related works.
[framework/osp/ime.git] / src / FUiIme_InputMethodImpl.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 /**
19  * @file        FUiIme_InputMethodImpl.cpp
20  * @brief       This is the implementation file for the %_InputMethodImpl class.
21  *
22  * This implementation file contains definition of the %_InputMethodImpl class.
23  */
24
25 #include <new>
26 #include <unique_ptr.h>
27
28 #include <Ecore_IMF.h>
29 #include <Ecore_X.h> // ecore_x_icccm_hints_get
30 #include <Elementary.h> // elm_win_keyboard_win_set
31
32 #include <FBaseSysLog.h>
33 #include <FGrpCoordinateSystem.h>
34
35 #include <FBase_StringConverter.h>
36
37 #include "FUi_EcoreEvas.h"
38 #include "FUi_EcoreEvasMgr.h"
39
40 #include "FUiIme_EcoreEventHandler.h"
41 #include "FUiIme_EcoreFdHandler.h"
42 #include "FUiIme_ImeInfo.h"
43 #include "FUiIme_InputMethodImpl.h"
44 #include "FUiIme_InputServiceSignalListener.h"
45 #include "FUiIme_ScimDataConverter.h"
46
47 using namespace Tizen::Base;
48 using namespace Tizen::Graphics;
49 using namespace Tizen::Ui;
50
51 namespace Tizen { namespace Ui { namespace Ime {
52
53 _InputMethodImpl::_InputMethodImpl(void)
54         :__pHelperAgent(null)
55         ,__pEcoreEventHandler(null)
56         ,__pEcoreFdHandler(null)
57         ,__pInputServiceBinder(null)
58 {
59 }
60
61 _InputMethodImpl::~_InputMethodImpl(void)
62 {
63         __pHelperAgent = null;
64
65         if (__pEcoreEventHandler)
66         {
67                 __pEcoreEventHandler->Deactivate();
68                 __pEcoreEventHandler = null;
69         }
70
71         if (__pEcoreFdHandler)
72         {
73                 __pEcoreFdHandler->Deactivate();
74                 __pEcoreFdHandler = null;
75         }
76
77         if (__pInputServiceBinder)
78         {
79                 __pInputServiceBinder->Unbind();
80                 __pInputServiceBinder = null;
81         }
82 }
83
84 result
85 _InputMethodImpl::Construct(void)
86 {
87         result r = E_SUCCESS;
88
89         __pInputServiceBinder = _InputServiceBinder::GetInstance();
90         r = GetLastResult();
91         SysTryReturnResult(NID_UI_IME, __pInputServiceBinder, r, "Propagating.");
92
93         BindingId bindingId = -1;
94         bindingId = __pInputServiceBinder->Bind();
95         r = GetLastResult();
96         SysTryCatch(NID_UI_IME, bindingId > -1, , r, "[%s] Propagating.", GetErrorMessage(r));
97
98         __pHelperAgent = __pInputServiceBinder->GetHelperAgent();
99
100         SetInputServiceSignalCallback();
101
102         r = SetInputPanelWindowAttribute();
103         SysTryCatch(NID_UI_IME, r == E_SUCCESS, , r, "[%s] Propagating.", GetErrorMessage(r));
104
105         __pEcoreEventHandler = _EcoreEventHandler::GetInstance();
106         r = GetLastResult();
107         SysTryCatch(NID_UI_IME, __pEcoreEventHandler, , r, "[%s] Propagating.", GetErrorMessage(r));
108
109         r = __pEcoreEventHandler->Activate();
110         SysTryCatch(NID_UI_IME, r == E_SUCCESS, , r, "[%s] Propagating.", GetErrorMessage(r));
111
112         __pEcoreFdHandler = _EcoreFdHandler::GetInstance(bindingId, *__pHelperAgent);
113         r = GetLastResult();
114         SysTryCatch(NID_UI_IME, __pEcoreFdHandler, , r, "[%s] Propagating.", GetErrorMessage(r));
115
116         r = __pEcoreFdHandler->Activate();
117         SysTryCatch(NID_UI_IME, r == E_SUCCESS, , r, "[%s] Propagating.", GetErrorMessage(r));
118
119         return r;
120
121 CATCH:
122         __pInputServiceBinder->Unbind();
123         __pInputServiceBinder = null;
124
125         __pHelperAgent = null;
126
127         if (__pEcoreEventHandler)
128         {
129                 __pEcoreEventHandler->Deactivate();
130                 __pEcoreEventHandler = null;
131         }
132
133         if (__pEcoreFdHandler)
134         {
135                 __pEcoreFdHandler->Deactivate();
136                 __pEcoreFdHandler = null;
137         }
138
139         return r;
140 }
141
142 _InputMethodImpl*
143 _InputMethodImpl::GetInstance(InputMethod& inputMethod)
144 {
145         return inputMethod.__pInputMethodImpl;
146 }
147
148 void
149 _InputMethodImpl::SetInputMethodProvider(IInputMethodProvider* pProvider)
150 {
151         _InputServiceSignalListener::SetInputMethodProvider(pProvider);
152 }
153
154 void
155 _InputMethodImpl::SetInputMethodProviderF(IInputMethodProviderF* pProvider)
156 {
157         _InputServiceSignalListener::SetInputMethodProviderF(pProvider);
158 }
159
160 void
161 _InputMethodImpl::SetInputMethodListener(IInputMethodListener* pListener)
162 {
163         _InputServiceSignalListener::SetInputMethodListener(pListener);
164 }
165
166 result
167 _InputMethodImpl::DeleteText(int cursorOffset, int length)
168 {
169         SysTryReturnResult(NID_UI_IME, length > 0, E_INVALID_ARG, "Invalid argument(s) is used. The length is not greater than 0.");
170
171         result r = E_SUCCESS;
172
173         __pHelperAgent->delete_surrounding_text(cursorOffset, length);
174
175         return r;
176 }
177
178 result
179 _InputMethodImpl::NotifyInputPanelBounds(const Tizen::Graphics::FloatRectangle& portraitBounds, const Tizen::Graphics::FloatRectangle& landscapeBounds)
180 {
181         result r = E_SUCCESS;
182
183         _EcoreEvasMgr* pEcoreEvasMgr = null;
184         pEcoreEvasMgr = GetEcoreEvasMgr();
185         r = GetLastResult();
186         SysTryReturnResult(NID_UI_IME, pEcoreEvasMgr, r, "Propagating.");
187
188         _EcoreEvas* pEcoreEvas = null;
189         pEcoreEvas = pEcoreEvasMgr->GetEcoreEvas();
190         r = GetLastResult();
191         SysTryReturnResult(NID_UI_IME, pEcoreEvas, r, "Propagating.");
192
193         Ecore_X_Window inputPanelWindow = pEcoreEvas->GetXWindow();
194
195         float width = CoordinateSystem::ConvertToPhysicalX(portraitBounds.width);
196         float height = CoordinateSystem::ConvertToPhysicalY(portraitBounds.height);
197         ecore_x_e_window_rotation_geometry_set(inputPanelWindow, 0, 0, 0, static_cast<int>(width), static_cast<int>(height));
198         ecore_x_e_window_rotation_geometry_set(inputPanelWindow, 180, 0, 0, static_cast<int>(width), static_cast<int>(height));
199
200         // give the size information according to the screen coordinates; the width should be replaced with the height and the reverse should be done in the same way
201         width = CoordinateSystem::ConvertToPhysicalX(landscapeBounds.width);
202         height = CoordinateSystem::ConvertToPhysicalY(landscapeBounds.height);
203         ecore_x_e_window_rotation_geometry_set(inputPanelWindow, 90, 0, 0, static_cast<int>(height), static_cast<int>(width));
204         ecore_x_e_window_rotation_geometry_set(inputPanelWindow, 270, 0, 0, static_cast<int>(height), static_cast<int>(width));
205
206         return r;
207 }
208
209 result
210 _InputMethodImpl::NotifyInputPanelState(InputPanelShowState state)
211 {
212         SysTryReturnResult(NID_UI_IME, (state == INPUT_PANEL_SHOW_STATE_SHOW) || (state == INPUT_PANEL_SHOW_STATE_HIDE), E_INVALID_ARG,
213                                         "Invalid argument(s) is used. The state is beyond the scope.");
214
215         result r = E_SUCCESS;
216
217         Ecore_IMF_Input_Panel_State inputPanelState;
218
219         switch (state)
220         {
221         case INPUT_PANEL_SHOW_STATE_SHOW:
222                 inputPanelState = ECORE_IMF_INPUT_PANEL_STATE_SHOW;
223                 break;
224         case INPUT_PANEL_SHOW_STATE_HIDE:
225                 inputPanelState = ECORE_IMF_INPUT_PANEL_STATE_HIDE;
226                 break;
227         default:
228                 break;
229         }
230
231         __pHelperAgent->update_input_context(ECORE_IMF_INPUT_PANEL_STATE_EVENT, inputPanelState);
232
233         return r;
234 }
235
236 result
237 _InputMethodImpl::NotifyLanguageChanged(void)
238 {
239         result r = E_SUCCESS;
240
241         __pHelperAgent->update_input_context(ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, 0);
242
243         return r;
244 }
245
246 result
247 _InputMethodImpl::RequestSurroundingText(int lengthBeforeCursor, int lengthAfterCursor)
248 {
249         SysTryReturnResult(NID_UI_IME, (lengthBeforeCursor >= 0) && (lengthAfterCursor >= 0), E_INVALID_ARG,
250                         "[E_INVALID_ARG] Invalid argument(s) is used. The length is not greater than or equal to 0.");
251
252         result r = E_SUCCESS;
253
254         _ImeInfo* pImeInfo = _ImeInfo::GetInstance();
255         scim::String uuid = pImeInfo->GetUuid();
256
257         __pHelperAgent->get_surrounding_text(uuid, lengthBeforeCursor, lengthAfterCursor);
258
259         return r;
260 }
261
262 result
263 _InputMethodImpl::SendCompositeText(const String& text)
264 {
265         result r = E_SUCCESS;
266
267         scim::WideString compositeText;
268         r = _ScimDataConverter::ConvertString(text, compositeText);
269         SysTryReturnResult(NID_UI_IME, r == E_SUCCESS, r, "Propagating.");
270
271         scim::AttributeList attributeList;
272         __pHelperAgent->update_preedit_string(-1, "", compositeText, attributeList);
273
274         return r;
275 }
276
277 result
278 _InputMethodImpl::SendKeyEvent(KeyCode code, KeyState state)
279 {
280         SysTryReturnResult(NID_UI_IME, (code > KEY_INVALID) && (code < KEY_HARDWARE_MAX), E_INVALID_ARG,
281                                         "Invalid argument(s) is used. The key code is beyond the scope.");
282         SysTryReturnResult(NID_UI_IME, (state >= KEY_PRESSED) && (state <= KEY_LONGPRESSED), E_INVALID_ARG,
283                                         "Invalid argument(s) is used. The key state is beyond the scope.");
284
285         result r = E_SUCCESS;
286
287         scim::KeyEvent keyEvent;
288         _ScimDataConverter::ConvertKey(code, state, keyEvent);
289         __pHelperAgent->forward_key_event(-1, "", keyEvent);
290
291         return r;
292 }
293
294 result
295 _InputMethodImpl::SendText(const String& text)
296 {
297         result r = E_SUCCESS;
298
299         scim::String scimText;
300         r = _ScimDataConverter::ConvertString(text, scimText);
301         SysTryReturnResult(NID_UI_IME, r == E_SUCCESS, r, "Propagating.");
302
303         scim::WideString wideString = scim::utf8_mbstowcs(scimText);
304
305         __pHelperAgent->commit_string(-1, "", wideString);
306
307         return r;
308 }
309
310 result
311 _InputMethodImpl::SetInputPanelWindowAttribute(void)
312 {
313         result r = E_SUCCESS;
314
315         _EcoreEvasMgr* pEcoreEvasMgr = null;
316         pEcoreEvasMgr = GetEcoreEvasMgr();
317         r = GetLastResult();
318         SysTryReturnResult(NID_UI_IME, pEcoreEvasMgr, r, "Propagating.");
319
320         _EcoreEvas* pEcoreEvas = null;
321         pEcoreEvas = pEcoreEvasMgr->GetEcoreEvas();
322         r = GetLastResult();
323         SysTryReturnResult(NID_UI_IME, pEcoreEvas, r, "Propagating.");
324
325         elm_win_keyboard_win_set(pEcoreEvas->GetWindowObject(), EINA_TRUE);
326
327         // for supporting rotation sync
328         Ecore_X_Window inputPanelWindow = elm_win_xwindow_get(pEcoreEvas->GetWindowObject());
329         SysLog(NID_UI_IME, "The handle of the input panel window is %x.", inputPanelWindow);
330         unsigned int value = 1;
331         ecore_x_window_prop_card32_set(inputPanelWindow, ECORE_X_ATOM_E_WINDOW_ROTATION_SUPPORTED, &value, 1);
332
333         // set x window id
334         const int _MAX_BUFFER_SIZE = 256;
335         char xId[_MAX_BUFFER_SIZE];
336         memset(xId, '\0', _MAX_BUFFER_SIZE);
337         snprintf(xId, _MAX_BUFFER_SIZE, "%d", inputPanelWindow);
338         scim::Property property(xId, "XID", "", "");
339         scim::PropertyList propertyList;
340         propertyList.push_back(property);
341         __pHelperAgent->register_properties(propertyList);
342
343         // set x window class name
344         ecore_x_icccm_name_class_set(inputPanelWindow, "Virtual Keyboard", "ISF");
345
346         // set hints in order not to get window focus
347         Eina_Bool accepts_focus = EINA_TRUE;
348         Ecore_X_Window_State_Hint initial_state = ECORE_X_WINDOW_STATE_HINT_NONE;
349         Ecore_X_Pixmap icon_pixmap = 0;
350         Ecore_X_Pixmap icon_mask = 0;
351         Ecore_X_Window icon_window = 0;
352         Ecore_X_Window window_group = 0;
353         Eina_Bool is_urgent = EINA_FALSE;
354
355         Eina_Bool result = EINA_FALSE;
356         result = ecore_x_icccm_hints_get(pEcoreEvas->GetXWindow(), &accepts_focus, &initial_state, &icon_pixmap, &icon_mask, &icon_window, &window_group, &is_urgent);
357         SysTryReturnResult(NID_UI_IME, result == EINA_TRUE, E_SYSTEM, "A failure occurs from the underlying system.");
358
359         ecore_x_icccm_hints_set(pEcoreEvas->GetXWindow(), EINA_FALSE, initial_state, icon_pixmap, icon_mask, icon_window, window_group, is_urgent);
360
361         return r;
362 }
363
364 void
365 _InputMethodImpl::SetInputServiceSignalCallback(void)
366 {
367         __pHelperAgent->signal_connect_get_geometry(scim::slot(_InputServiceSignalListener::GetInputPanelBounds));
368         __pHelperAgent->signal_connect_get_layout(scim::slot(_InputServiceSignalListener::GetInputPanelStyle));
369         __pHelperAgent->signal_connect_get_language_locale(scim::slot(_InputServiceSignalListener::GetLanguage));
370         __pHelperAgent->signal_connect_get_return_key_disable(scim::slot(_InputServiceSignalListener::IsEnterKeyActionEnabled));
371         __pHelperAgent->signal_connect_get_return_key_type(scim::slot(_InputServiceSignalListener::GetEnterKeyAction));
372
373         __pHelperAgent->signal_connect_set_caps_mode(scim::slot(_InputServiceSignalListener::SetCapsModeEnabled));
374         __pHelperAgent->signal_connect_set_language(scim::slot(_InputServiceSignalListener::SetLanguage));
375         __pHelperAgent->signal_connect_set_layout(scim::slot(_InputServiceSignalListener::SetInputPanelStyle));
376         __pHelperAgent->signal_connect_set_return_key_disable(scim::slot(_InputServiceSignalListener::SetEnterKeyActionEnabled));
377         __pHelperAgent->signal_connect_set_return_key_type(scim::slot(_InputServiceSignalListener::SetEnterKeyAction));
378
379         __pHelperAgent->signal_connect_ise_hide(scim::slot(_InputServiceSignalListener::HideInputPanel));
380         __pHelperAgent->signal_connect_ise_show(scim::slot(_InputServiceSignalListener::ShowInputPanel));
381
382         __pHelperAgent->signal_connect_update_cursor_position(scim::slot(_InputServiceSignalListener::OnCursorPositionChanged));
383         __pHelperAgent->signal_connect_set_imdata(scim::slot(_InputServiceSignalListener::OnOpaqueCommandReceived));
384         __pHelperAgent->signal_connect_update_surrounding_text(scim::slot(_InputServiceSignalListener::OnSurroundingTextReceived));
385
386         __pHelperAgent->signal_connect_exit(scim::slot(_InputServiceSignalListener::OnTerminate));
387
388         SysLog(NID_UI_IME, "The signal callback functions of the input service have been set");
389 }
390
391 void
392 _InputMethodImpl::HideInputPanel(void)
393 {
394         _EcoreEvasMgr* pEcoreEvasMgr = null;
395         pEcoreEvasMgr = GetEcoreEvasMgr();
396         SysTryReturnVoidResult(NID_UI_IME, pEcoreEvasMgr, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] The required instance does not exist.");
397
398         _EcoreEvas* pEcoreEvas = null;
399         pEcoreEvas = pEcoreEvasMgr->GetEcoreEvas();
400         SysTryReturnVoidResult(NID_UI_IME, pEcoreEvas, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] The required instance does not exist.");
401
402         Evas_Object* pEvasObject = null;
403         pEvasObject = pEcoreEvas->GetWindowObject();
404         SysTryReturnVoidResult(NID_UI_IME, pEvasObject, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] The required instance does not exist.");
405
406         if (evas_object_visible_get(pEvasObject))
407         {
408                 evas_object_hide(pEvasObject);
409         }
410 }
411
412 void
413 _InputMethodImpl::ShowInputPanel(void)
414 {
415         _EcoreEvasMgr* pEcoreEvasMgr = null;
416         pEcoreEvasMgr = GetEcoreEvasMgr();
417         SysTryReturnVoidResult(NID_UI_IME, pEcoreEvasMgr, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] The required instance does not exist.");
418
419         _EcoreEvas* pEcoreEvas = null;
420         pEcoreEvas = pEcoreEvasMgr->GetEcoreEvas();
421         SysTryReturnVoidResult(NID_UI_IME, pEcoreEvas, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] The required instance does not exist.");
422
423         Evas_Object* pEvasObject = null;
424         pEvasObject = pEcoreEvas->GetWindowObject();
425         SysTryReturnVoidResult(NID_UI_IME, pEvasObject, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] The required instance does not exist.");
426
427         if (evas_object_visible_get(pEvasObject) == false)
428         {
429                 evas_object_show(pEvasObject);
430         }
431 }
432
433 }}} // Tizen::Ui::Ime