Revert "Make lws_create_context() to fail if unable to bind"
[platform/core/uifw/libscl-core.git] / src / legacy_support / websocket.cpp
1 /*
2  * Copyright (c) 2012 - 2016 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 <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <getopt.h>
22 #include <string.h>
23 #include <sys/time.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <assert.h>
27 #include <Ecore.h>
28 #include <Ecore_IMF.h>
29 #include <dlog.h>
30
31 #include "websocket.h"
32
33 #include <syslog.h>
34 #include <signal.h>
35
36 #include <libwebsockets.h>
37
38 #ifdef WAYLAND
39 #define EFL_BETA_API_SUPPORT
40 #include <Ecore_Wl2.h>
41 #endif
42
43 #define WEBSOCKET_PORT 7681
44
45 #define RECVED_MESSAGE "recved"
46 #define MESSAGE_LEFT "left"
47
48 pthread_t g_ws_server_thread = (pthread_t)NULL;
49 pthread_mutex_t g_ws_server_mutex = PTHREAD_MUTEX_INITIALIZER;
50
51 pthread_cond_t g_ws_query_condition = PTHREAD_COND_INITIALIZER;
52 pthread_mutex_t g_ws_query_mutex = PTHREAD_MUTEX_INITIALIZER;
53
54 bool g_ws_server_exit = false;
55 struct lws_context *g_ws_server_context = NULL;
56
57 CWebHelperAgentWebSocket* CWebHelperAgentWebSocket::m_current_instance = NULL;
58
59 int force_exit = 0;
60
61 enum protocols {
62     /* always first */
63     PROTOCOL_HTTP = 0,
64
65     PROTOCOL_KEYBOARD,
66
67     /* always last */
68     MAX_PROTOCOL_COUNT
69 };
70
71 struct per_session_data__http {
72     int fd;
73 };
74
75 static int callback_http(struct lws *wsi,
76         enum lws_callback_reasons reason,
77         void *user, void *in, size_t len)
78 {
79     return 0;
80 }
81
82 struct per_session_data__keyboard {
83     int session_id;
84     int valid;
85     int need_init;
86     int initialized;
87 };
88
89 static int callback_keyboard(struct lws *wsi,
90         enum lws_callback_reasons reason,
91         void *user, void *in, size_t len);
92
93 static struct lws_protocols protocols[] = {
94     {
95         "http-only",
96         callback_http,
97         sizeof(struct per_session_data__http),
98         0,
99     },
100     {
101         "keyboard-protocol",
102         callback_keyboard,
103         sizeof(struct per_session_data__keyboard),
104         32,
105     },
106     { NULL, NULL, 0, 0 }
107 };
108
109
110 static int callback_client(struct lws *wsi,
111     enum lws_callback_reasons reason,
112     void *user, void *in, size_t len)
113 {
114     switch (reason) {
115     case LWS_CALLBACK_CLIENT_ESTABLISHED:
116         LOGD("[ClientTest] Connection established");
117         break;
118
119     case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
120         LOGD("[ClientTest] Connection error");
121         break;
122
123     case LWS_CALLBACK_CLOSED:
124         LOGD("[ClientTest] Connection closed");
125         break;
126
127     default:
128         break;
129     }
130
131     return 0;
132 }
133
134 int test_client_connection(void)
135 {
136     struct lws_context *context = NULL;
137     struct lws_context_creation_info context_info;
138     struct lws_client_connect_info connect_info;
139     struct lws *wsi = NULL;
140
141     memset(&context_info, 0, sizeof context_info);
142     memset(&connect_info, 0, sizeof(connect_info));
143
144     const int protocols_num = sizeof(protocols) / sizeof(lws_protocols);
145     static struct lws_protocols client_protocols[protocols_num];
146
147     memcpy(&client_protocols, protocols, sizeof(protocols));
148     for (int loop = 0; loop < protocols_num - 1; loop++) {
149         client_protocols[loop].callback = callback_client;
150     }
151
152     context_info.port = CONTEXT_PORT_NO_LISTEN;
153     context_info.protocols = protocols;
154     context_info.gid = -1;
155     context_info.uid = -1;
156
157     context = lws_create_context(&context_info);
158     LOGD("[ClientTest] create_context : %p", context);
159     if (context == NULL) {
160         return -1;
161     }
162
163     connect_info.address = "localhost";
164     connect_info.port = WEBSOCKET_PORT;
165     connect_info.path = "/";
166     connect_info.context = context;
167     connect_info.ssl_connection = 0;
168     connect_info.host = connect_info.address;
169     connect_info.origin = connect_info.address;
170     connect_info.ietf_version_or_minus_one = -1;
171     connect_info.protocol = "keyboard-protocol";
172
173     wsi = lws_client_connect_via_info(&connect_info);
174     LOGD("[ClientTest] wsi created : %p", wsi);
175
176     if (wsi) {
177         lws_service(context, 50);
178     }
179
180     lws_context_destroy(context);
181
182     return 0;
183 }
184
185 static Ecore_Timer *g_flush_server_recv_buffer_timer = NULL;
186 static std::string server_recv_buffer;
187 static Eina_Bool flush_server_recv_buffer_func(void *user)
188 {
189     LOGD("flushing recv buffer");
190     CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance();
191     struct per_session_data__keyboard *pss = (struct per_session_data__keyboard *)user;
192
193     if (g_flush_server_recv_buffer_timer)
194         ecore_timer_del(g_flush_server_recv_buffer_timer);
195     g_flush_server_recv_buffer_timer = NULL;
196
197     if (!agent || !pss) return ECORE_CALLBACK_CANCEL;
198
199     pthread_mutex_lock(&g_ws_server_mutex);
200     ISE_MESSAGE message = CISEMessageSerializer::deserialize(server_recv_buffer);
201     server_recv_buffer.clear();
202     pthread_mutex_unlock(&g_ws_server_mutex);
203
204     if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOGIN]) == 0) {
205         /*
206            if (message.values.at(0).compare(CMagicKeyManager::get_magic_key()) == 0) {
207            LOGD("LOGIN successful, validating client");
208            pss->valid = true;
209            } else {
210            LOGD("LOGIN failed, invalidating client");
211            pss->valid = false;
212            }
213            */
214         pss->valid = true;
215
216         if (agent->initalized()) {
217             pss->need_init = true;
218             ecore_pipe_write(agent->get_message_pipe(), MESSAGE_LEFT, strlen(MESSAGE_LEFT));
219         }
220     }
221
222     /* Ignore valid check since the magic key is not used anymore */
223     if (!pss->valid) pss->valid = true;
224
225     if (pss->valid) {
226         pthread_mutex_lock(&g_ws_server_mutex);
227         std::queue<ISE_MESSAGE>& messages = agent->get_recv_message_queue();
228         messages.push(message);
229         pthread_mutex_unlock(&g_ws_server_mutex);
230
231         ecore_pipe_write(agent->get_message_pipe(), RECVED_MESSAGE, strlen(RECVED_MESSAGE));
232
233         /* If we received reply message, let's send signal to wake up our main thread */
234         if (message.type.compare(ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]) == 0) {
235             pthread_mutex_lock(&g_ws_query_mutex);
236             pthread_cond_signal(&g_ws_query_condition);
237             pthread_mutex_unlock(&g_ws_query_mutex);
238         }
239     } else {
240         LOGD("Ignoring data received since client is not valid %d", pss->session_id);
241     }
242
243     return ECORE_CALLBACK_CANCEL;
244 }
245
246 static int callback_keyboard(struct lws *wsi,
247         enum lws_callback_reasons reason,
248         void *user, void *in, size_t len)
249 {
250     static int last_session_id = 0;
251     const int bufsize = 512;
252     int n = 0;
253     unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + bufsize +
254                           LWS_SEND_BUFFER_POST_PADDING];
255     unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
256     struct per_session_data__keyboard *pss = (struct per_session_data__keyboard *)user;
257     CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance();
258
259     switch (reason) {
260     case LWS_CALLBACK_ESTABLISHED:
261         pss->session_id = ++last_session_id;
262         LOGD("LWS_CALLBACK_ESTABLISHED : %p %d", g_ws_server_context, pss->session_id);
263         pss->valid = false;
264         pss->need_init = false;
265         pss->initialized = false;
266         if (g_ws_server_context) {
267             ecore_pipe_write(agent->get_message_pipe(), MESSAGE_LEFT, strlen(MESSAGE_LEFT));
268         }
269         break;
270
271     case LWS_CALLBACK_CLOSED:
272         LOGD("LWS_CALLBACK_CLOSED : %d", pss->session_id);
273         break;
274
275     case LWS_CALLBACK_SERVER_WRITEABLE:
276         if (agent) {
277             /* Ignore valid check since the magic key is not used anymore */
278             if (!pss->valid) pss->valid = true;
279
280             /* We allow data tranmission only if this client is guaranteed to be valid */
281             if (pss->valid) {
282                 pthread_mutex_lock(&g_ws_server_mutex);
283                 std::queue<ISE_MESSAGE>& messages = agent->get_send_message_queue();
284
285                 if (pss->need_init && !pss->initialized) {
286                     ISE_MESSAGE message;
287                     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
288                     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT];
289                     std::string str = CISEMessageSerializer::serialize(message);
290                     SECURE_LOGD("SEND_WEBSOCKET_MESSAGE : %d %s", pss->session_id, str.c_str());
291                     n = snprintf((char *)p, bufsize, "%s", str.c_str());
292                     /* too small for partial */
293                     n = lws_write(wsi, p, n, LWS_WRITE_TEXT);
294                     pss->need_init = false;
295                     pss->initialized = true;
296                 } else {
297                     /* One write allowed per one writable callback */
298                     if (messages.size() > 0) {
299                         ISE_MESSAGE &message = messages.front();
300                         bool drop = false;
301                         if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT]) == 0) {
302                             if (pss->initialized) {
303                                 drop = true;
304                             } else {
305                                 pss->initialized = true;
306                             }
307                         }
308                         if (!drop) {
309                             std::string str = CISEMessageSerializer::serialize(message);
310                             SECURE_LOGD("SEND_WEBSOCKET_MESSAGE : %d %s", pss->session_id, str.c_str());
311                             n = snprintf((char *)p, bufsize, "%s", str.c_str());
312                             /* too small for partial */
313                             n = lws_write(wsi, p, n, LWS_WRITE_TEXT);
314                         }
315                         messages.pop();
316                     }
317                 }
318                 if (messages.size() > 0) {
319                     ecore_pipe_write(agent->get_message_pipe(), MESSAGE_LEFT, strlen(MESSAGE_LEFT));
320                 }
321                 pthread_mutex_unlock(&g_ws_server_mutex);
322
323                 if (n < 0) {
324                     LOGE("ERROR %d writing to di socket %d", n, pss->session_id);
325                 }
326
327                 if (messages.size() > 0) {
328                     lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
329                 }
330             } else {
331                 LOGD("Rejecting data transmission since client is not valid : %d", pss->session_id);
332             }
333         }
334         break;
335
336     case LWS_CALLBACK_RECEIVE:
337         if (in) {
338             if (g_flush_server_recv_buffer_timer) {
339                 ecore_thread_main_loop_begin();
340                 ecore_timer_del(g_flush_server_recv_buffer_timer);
341                 g_flush_server_recv_buffer_timer = NULL;
342                 ecore_thread_main_loop_end();
343             }
344
345             std::string str = (const char *)in;
346             if (CISEMessageSerializer::valid(str)) {
347                 LOGD("A valid new message received, flush previous buffer");
348                 flush_server_recv_buffer_func((void*)pss);
349             }
350
351             pthread_mutex_lock(&g_ws_server_mutex);
352             server_recv_buffer += str;
353             SECURE_LOGD("RECEIVE callback : [%s], [%s]", str.c_str(), server_recv_buffer.c_str());
354             pthread_mutex_unlock(&g_ws_server_mutex);
355
356             ecore_thread_main_loop_begin();
357             g_flush_server_recv_buffer_timer = ecore_timer_add(0.05, flush_server_recv_buffer_func, (void*)pss);
358             SECURE_LOGD("flush timer registered : %p", g_flush_server_recv_buffer_timer);
359             ecore_thread_main_loop_end();
360         }
361
362         break;
363     default:
364         break;
365     }
366
367     return 0;
368 }
369
370 void *process_ws_server(void *data)
371 {
372     while (!force_exit && !g_ws_server_exit) {
373         struct timeval tv;
374         gettimeofday(&tv, NULL);
375
376         if (g_ws_server_context) {
377             lws_service(g_ws_server_context, 50);
378         } else {
379             LOGD("WARNING : g_ws_server_context is NULL");
380         }
381     }
382     LOGD("process_ws_server exits now");
383     return NULL;
384 }
385
386 void log_func(int level, const char *line)
387 {
388     if (line) {
389         LOGD("LEVEL : %d , %s", level, line);
390     }
391 }
392
393 CWebHelperAgentWebSocket::CWebHelperAgentWebSocket()
394 {
395     if (m_current_instance != NULL) {
396         LOGD("WARNING : m_current_instance is NOT NULL");
397     }
398     m_current_instance = this;
399     m_message_pipe = NULL;
400     m_initialized = false;
401 }
402
403 CWebHelperAgentWebSocket::~CWebHelperAgentWebSocket()
404 {
405     if (m_current_instance == this) {
406         m_current_instance = NULL;
407     }
408
409     if (m_message_pipe) {
410         ecore_pipe_del(m_message_pipe);
411         m_message_pipe = NULL;
412     }
413 }
414
415 static void message_pipe_handler(void *data, void *buffer, unsigned int nbyte)
416 {
417     if (buffer) {
418         if (strncmp((const char*)buffer, RECVED_MESSAGE, strlen(RECVED_MESSAGE)) == 0) {
419             CWebHelperAgentWebSocket *agent = CWebHelperAgentWebSocket::get_current_instance();
420             if (agent) {
421                 agent->process_recved_messages();
422             }
423         } else {
424             if (g_ws_server_context) {
425                 lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
426             } else {
427                 LOGD("WARNING : g_ws_server_context is NULL");
428             }
429         }
430     }
431 }
432
433 bool CWebHelperAgentWebSocket::init()
434 {
435     bool ret = true;
436
437     struct lws_context_creation_info info;
438
439     memset(&info, 0, sizeof info);
440     info.port = WEBSOCKET_PORT;
441
442     int log_level = LLL_ERR | LLL_WARN | LLL_DEBUG;
443     lws_set_log_level(log_level, log_func);
444
445     info.iface = NULL;
446     info.protocols = protocols;
447     info.extensions = NULL;
448     info.ssl_cert_filepath = NULL;
449     info.ssl_private_key_filepath = NULL;
450     info.gid = -1;
451     info.uid = -1;
452     info.options = 0;
453
454     ecore_init();
455
456     /* The WebSocket server is running on a separate thread, and let the thread send a message
457         through this pipe to guarantee thread safety */
458     m_message_pipe = ecore_pipe_add(message_pipe_handler, NULL);
459
460     /* Let's retry creating server context for a certain number of times */
461     const int max_retry_num = 30;
462     int retry_num = 0;
463
464     do {
465         g_ws_server_context = lws_create_context(&info);
466         LOGD("libwebsocket context : %p", g_ws_server_context);
467         usleep(100 * 1000);
468     } while (g_ws_server_context == NULL && retry_num++ < max_retry_num);
469
470     pthread_mutex_init(&g_ws_server_mutex, NULL);
471
472     pthread_mutex_init(&g_ws_query_mutex, NULL);
473     pthread_cond_init(&g_ws_query_condition, NULL);
474
475     if (g_ws_server_context) {
476         if (pthread_create(&g_ws_server_thread, NULL, &process_ws_server, NULL) != 0) {
477             g_ws_server_thread = (pthread_t)NULL;
478             ret = false;
479         }
480     } else {
481         LOGE("Failed creating server context : %p", g_ws_server_context);
482         ret = false;
483     }
484
485     on_init();
486
487     m_initialized = true;
488
489     test_client_connection();
490
491     return ret;
492 }
493
494 bool CWebHelperAgentWebSocket::exit()
495 {
496     if (g_flush_server_recv_buffer_timer)
497         ecore_timer_del(g_flush_server_recv_buffer_timer);
498     g_flush_server_recv_buffer_timer = NULL;
499
500     on_exit();
501
502     g_ws_server_exit = true;
503     if (g_ws_server_context) {
504         lws_cancel_service(g_ws_server_context);
505     }
506
507     if (m_message_pipe) {
508         ecore_pipe_del(m_message_pipe);
509         m_message_pipe = NULL;
510     }
511
512     if (g_ws_server_thread) {
513         pthread_join(g_ws_server_thread, NULL);
514     }
515
516     pthread_cond_destroy(&g_ws_query_condition);
517     pthread_mutex_destroy(&g_ws_query_mutex);
518
519     pthread_mutex_destroy(&g_ws_server_mutex);
520
521     if (g_ws_server_context) {
522         lws_context_destroy(g_ws_server_context);
523         g_ws_server_context = NULL;
524     }
525
526     ecore_shutdown();
527
528     return true;
529 }
530
531 void CWebHelperAgentWebSocket::signal(int sig)
532 {
533     force_exit = 1;
534 }
535
536 template<class T>
537 std::string to_string(T i)
538 {
539     std::stringstream ss;
540     std::string s;
541     ss << i;
542     s = ss.str();
543
544     return s;
545 }
546
547 void CWebHelperAgentWebSocket::on_init()
548 {
549     ISE_MESSAGE message;
550     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
551     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_INIT];
552
553     pthread_mutex_lock(&g_ws_server_mutex);
554     m_send_message_queue.push(message);
555     pthread_mutex_unlock(&g_ws_server_mutex);
556
557     if (g_ws_server_context) {
558         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
559     } else {
560         LOGD("WARNING : g_ws_server_context is NULL");
561     }
562 }
563
564 void CWebHelperAgentWebSocket::on_exit()
565 {
566     ISE_MESSAGE message;
567     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
568     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_EXIT];
569
570     pthread_mutex_lock(&g_ws_server_mutex);
571     m_send_message_queue.push(message);
572     pthread_mutex_unlock(&g_ws_server_mutex);
573
574     if (g_ws_server_context) {
575         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
576     } else {
577         LOGD("WARNING : g_ws_server_context is NULL");
578     }
579 }
580
581 void CWebHelperAgentWebSocket::on_focus_in(int ic)
582 {
583     ISE_MESSAGE message;
584     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
585     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_FOCUS_IN];
586     message.values.push_back(to_string(ic));
587
588     pthread_mutex_lock(&g_ws_server_mutex);
589     m_send_message_queue.push(message);
590     pthread_mutex_unlock(&g_ws_server_mutex);
591
592     if (g_ws_server_context) {
593         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
594     } else {
595         LOGD("WARNING : g_ws_server_context is NULL");
596     }
597 }
598
599 void CWebHelperAgentWebSocket::on_focus_out(int ic)
600 {
601     ISE_MESSAGE message;
602     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
603     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_FOCUS_OUT];
604     message.values.push_back(to_string(ic));
605
606     pthread_mutex_lock(&g_ws_server_mutex);
607     m_send_message_queue.push(message);
608     pthread_mutex_unlock(&g_ws_server_mutex);
609
610     if (g_ws_server_context) {
611         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
612     } else {
613         LOGD("WARNING : g_ws_server_context is NULL");
614     }
615 }
616
617 void CWebHelperAgentWebSocket::on_show(int ic)
618 {
619     ISE_MESSAGE message;
620     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
621     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SHOW];
622     message.values.push_back(to_string(ic));
623
624     pthread_mutex_lock(&g_ws_server_mutex);
625     m_send_message_queue.push(message);
626     pthread_mutex_unlock(&g_ws_server_mutex);
627
628     if (g_ws_server_context) {
629         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
630     } else {
631         LOGD("WARNING : g_ws_server_context is NULL");
632     }
633
634     LOGD("put into send message buffer");
635 }
636
637 void CWebHelperAgentWebSocket::on_hide(int ic)
638 {
639     ISE_MESSAGE message;
640     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
641     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_HIDE];
642     message.values.push_back(to_string(ic));
643
644     pthread_mutex_lock(&g_ws_server_mutex);
645     m_send_message_queue.push(message);
646     pthread_mutex_unlock(&g_ws_server_mutex);
647
648     if (g_ws_server_context) {
649         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
650     } else {
651         LOGD("WARNING : g_ws_server_context is NULL");
652     }
653 }
654
655 void CWebHelperAgentWebSocket::on_set_rotation(int degree)
656 {
657     ISE_MESSAGE message;
658     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
659     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_ROTATION];
660     message.values.push_back(to_string(degree));
661
662     pthread_mutex_lock(&g_ws_server_mutex);
663     m_send_message_queue.push(message);
664     pthread_mutex_unlock(&g_ws_server_mutex);
665
666     if (g_ws_server_context) {
667         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
668     } else {
669         LOGD("WARNING : g_ws_server_context is NULL");
670     }
671 }
672
673 void CWebHelperAgentWebSocket::on_update_cursor_position(int ic, int cursor_pos)
674 {
675     ISE_MESSAGE message;
676     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
677     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_CURSOR_POSITION];
678     message.values.push_back(to_string(ic));
679     message.values.push_back(to_string(cursor_pos));
680
681     pthread_mutex_lock(&g_ws_server_mutex);
682     m_send_message_queue.push(message);
683     pthread_mutex_unlock(&g_ws_server_mutex);
684
685     if (g_ws_server_context) {
686         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
687     } else {
688         LOGD("WARNING : g_ws_server_context is NULL");
689     }
690 }
691
692 void CWebHelperAgentWebSocket::on_update_surrounding_text(int ic, const char *text, int cursor)
693 {
694     ISE_MESSAGE message;
695     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY];
696     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_SURROUNDING_TEXT];
697     message.values.push_back(to_string(cursor));
698     message.values.push_back(text);
699
700     pthread_mutex_lock(&g_ws_server_mutex);
701     m_send_message_queue.push(message);
702     pthread_mutex_unlock(&g_ws_server_mutex);
703
704     if (g_ws_server_context) {
705         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
706     } else {
707         LOGD("WARNING : g_ws_server_context is NULL");
708     }
709 }
710
711 void CWebHelperAgentWebSocket::on_update_selection(int ic, const char *text)
712 {
713     ISE_MESSAGE message;
714     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY];
715     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_SELECTION];
716     message.values.push_back(text);
717
718     pthread_mutex_lock(&g_ws_server_mutex);
719     m_send_message_queue.push(message);
720     pthread_mutex_unlock(&g_ws_server_mutex);
721
722     if (g_ws_server_context) {
723         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
724     } else {
725         LOGD("WARNING : g_ws_server_context is NULL");
726     }
727 }
728
729 void CWebHelperAgentWebSocket::on_set_language(unsigned int language)
730 {
731     ISE_MESSAGE message;
732     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
733     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_LANGUAGE];
734
735     bool found = false;
736     for (unsigned int loop = 0;loop < sizeof(ISE_LANGUAGE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
737         if (language == (unsigned int)ISE_LANGUAGE_TYPES[loop].type_value) {
738             message.values.push_back(ISE_LANGUAGE_TYPES[loop].type_string);
739             found = true;
740         }
741     }
742
743     if (found) {
744         pthread_mutex_lock(&g_ws_server_mutex);
745         m_send_message_queue.push(message);
746         pthread_mutex_unlock(&g_ws_server_mutex);
747
748         if (g_ws_server_context) {
749             lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
750         } else {
751             LOGD("WARNING : g_ws_server_context is NULL");
752         }
753     }
754 }
755
756 void CWebHelperAgentWebSocket::on_set_imdata(char *buf, unsigned int len)
757 {
758     ISE_MESSAGE message;
759     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
760     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_IMDATA];
761     message.values.push_back(buf);
762
763     pthread_mutex_lock(&g_ws_server_mutex);
764     m_send_message_queue.push(message);
765     pthread_mutex_unlock(&g_ws_server_mutex);
766
767     if (g_ws_server_context) {
768         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
769     } else {
770         LOGD("WARNING : g_ws_server_context is NULL");
771     }
772 }
773
774 void CWebHelperAgentWebSocket::on_get_imdata(char **buf, unsigned int *len)
775 {
776     ISE_MESSAGE message;
777     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
778     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_IMDATA];
779
780     pthread_mutex_lock(&g_ws_server_mutex);
781     m_send_message_queue.push(message);
782     pthread_mutex_unlock(&g_ws_server_mutex);
783
784     if (g_ws_server_context) {
785         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
786     } else {
787         LOGD("WARNING : g_ws_server_context is NULL");
788     }
789
790     wait_for_reply_message();
791
792     std::vector<std::string> values;
793     /* Check if we received reply for GET_IMDATA message */
794     if (process_recved_messages_until_reply_found(
795         ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_IMDATA], values)) {
796             if (values.size() > 0 && buf && len) {
797                 int string_length = values.at(0).length();
798                 (*buf) = new char[string_length + 1];
799                 if (*buf) {
800                     strncpy(*buf, values.at(0).c_str(), string_length);
801                     /* Make sure this is a null-terminated string */
802                     *(*buf + string_length) = '\0';
803                     *len = string_length;
804                 }
805             }
806     } else {
807         LOGD("process_recved_messages_until_reply_found returned FALSE");
808     }
809     /* Now process the rest in the recv buffer */
810     process_recved_messages();
811 }
812
813 void CWebHelperAgentWebSocket::on_set_return_key_type(unsigned int type)
814 {
815     ISE_MESSAGE message;
816     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
817     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_RETURN_KEY_TYPE];
818
819     bool found = false;
820     for (unsigned int loop = 0;loop < sizeof(ISE_RETURN_KEY_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
821         if (type == (unsigned int)ISE_RETURN_KEY_TYPES[loop].type_value) {
822             message.values.push_back(ISE_RETURN_KEY_TYPES[loop].type_string);
823             found = true;
824         }
825     }
826
827     if (found) {
828         pthread_mutex_lock(&g_ws_server_mutex);
829         m_send_message_queue.push(message);
830         pthread_mutex_unlock(&g_ws_server_mutex);
831
832         if (g_ws_server_context) {
833             lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
834         } else {
835             LOGD("WARNING : g_ws_server_context is NULL");
836         }
837     }
838 }
839
840 void CWebHelperAgentWebSocket::on_get_return_key_type(unsigned int *type)
841 {
842     ISE_MESSAGE message;
843     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
844     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE];
845
846     pthread_mutex_lock(&g_ws_server_mutex);
847     m_send_message_queue.push(message);
848     pthread_mutex_unlock(&g_ws_server_mutex);
849
850     if (g_ws_server_context) {
851         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
852     } else {
853         LOGD("WARNING : g_ws_server_context is NULL");
854     }
855
856     wait_for_reply_message();
857
858     std::vector<std::string> values;
859     /* Check if we received reply for GET_RETURN_KEY_TYPE message */
860     if (process_recved_messages_until_reply_found(
861         ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_TYPE], values)) {
862             if (type) {
863                 for (unsigned int loop = 0;loop < sizeof(ISE_RETURN_KEY_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
864                     if (values.at(0).compare(ISE_RETURN_KEY_TYPES[loop].type_string) == 0) {
865                         *type = ISE_RETURN_KEY_TYPES[loop].type_value;
866                     }
867                 }
868             }
869     }
870     /* Now process the rest in the recv buffer */
871     process_recved_messages();
872 }
873
874 void CWebHelperAgentWebSocket::on_set_return_key_disable(unsigned int disabled)
875 {
876     ISE_MESSAGE message;
877     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
878     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_RETURN_KEY_DISABLE];
879
880     bool found = false;
881     for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
882         if (disabled == (unsigned int)ISE_TRUEFALSE_TYPES[loop].type_value) {
883             message.values.push_back(ISE_TRUEFALSE_TYPES[loop].type_string);
884             found = true;
885         }
886     }
887
888     if (found) {
889         pthread_mutex_lock(&g_ws_server_mutex);
890         m_send_message_queue.push(message);
891         pthread_mutex_unlock(&g_ws_server_mutex);
892
893         if (g_ws_server_context) {
894             lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
895         } else {
896             LOGD("WARNING : g_ws_server_context is NULL");
897         }
898     }
899 }
900
901 void CWebHelperAgentWebSocket::on_get_return_key_disable(unsigned int *disabled)
902 {
903     ISE_MESSAGE message;
904     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
905     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE];
906
907     pthread_mutex_lock(&g_ws_server_mutex);
908     m_send_message_queue.push(message);
909     pthread_mutex_unlock(&g_ws_server_mutex);
910
911     if (g_ws_server_context) {
912         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
913     } else {
914         LOGD("WARNING : g_ws_server_context is NULL");
915     }
916
917     wait_for_reply_message();
918
919     std::vector<std::string> values;
920     /* Check if we received reply for GET_RETURN_KEY_DISABLE message */
921     if (process_recved_messages_until_reply_found(
922         ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_RETURN_KEY_DISABLE], values)) {
923             if (disabled) {
924                 for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
925                     if (values.at(0).compare(ISE_TRUEFALSE_TYPES[loop].type_string) == 0) {
926                         *disabled = ISE_TRUEFALSE_TYPES[loop].type_value;
927                     }
928                 }
929             }
930     }
931     /* Now process the rest in the recv buffer */
932     process_recved_messages();
933 }
934
935 void CWebHelperAgentWebSocket::on_set_layout(unsigned int layout)
936 {
937     ISE_MESSAGE message;
938     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
939     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_LAYOUT];
940
941     bool found = false;
942     for (unsigned int loop = 0;loop < sizeof(ISE_LAYOUT_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
943         if (layout == (unsigned int)ISE_LAYOUT_TYPES[loop].type_value) {
944             message.values.push_back(ISE_LAYOUT_TYPES[loop].type_string);
945             found = true;
946         }
947     }
948
949     if (found) {
950         pthread_mutex_lock(&g_ws_server_mutex);
951         m_send_message_queue.push(message);
952         pthread_mutex_unlock(&g_ws_server_mutex);
953
954         if (g_ws_server_context) {
955             lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
956         } else {
957             LOGD("WARNING : g_ws_server_context is NULL");
958         }
959     }
960 }
961
962 void CWebHelperAgentWebSocket::on_get_layout(unsigned int *layout)
963 {
964     ISE_MESSAGE message;
965     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
966     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_LAYOUT];
967
968     pthread_mutex_lock(&g_ws_server_mutex);
969     m_send_message_queue.push(message);
970     pthread_mutex_unlock(&g_ws_server_mutex);
971
972     if (g_ws_server_context) {
973         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
974     } else {
975         LOGD("WARNING : g_ws_server_context is NULL");
976     }
977
978     wait_for_reply_message();
979
980     std::vector<std::string> values;
981     /* Check if we received reply for GET_LAYOUT message */
982     if (process_recved_messages_until_reply_found(
983         ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_LAYOUT], values)) {
984             if (layout) {
985                 for (unsigned int loop = 0;loop < sizeof(ISE_LAYOUT_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
986                     if (values.at(0).compare(ISE_LAYOUT_TYPES[loop].type_string) == 0) {
987                         *layout = ISE_LAYOUT_TYPES[loop].type_value;
988                     }
989                 }
990             }
991     }
992     /* Now process the rest in the recv buffer */
993     process_recved_messages();
994 }
995
996 void CWebHelperAgentWebSocket::on_reset_input_context(int ic)
997 {
998     ISE_MESSAGE message;
999     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_PLAIN];
1000     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_RESET_INPUT_CONTEXT];
1001     message.values.push_back(to_string(ic));
1002
1003     pthread_mutex_lock(&g_ws_server_mutex);
1004     m_send_message_queue.push(message);
1005     pthread_mutex_unlock(&g_ws_server_mutex);
1006
1007     if (g_ws_server_context) {
1008         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
1009     } else {
1010         LOGD("WARNING : g_ws_server_context is NULL");
1011     }
1012 }
1013
1014 void CWebHelperAgentWebSocket::on_process_key_event(unsigned int code, unsigned int mask, unsigned int layout, unsigned int *ret)
1015 {
1016     ISE_MESSAGE message;
1017     message.type = ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_QUERY];
1018     message.command = ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT];
1019     message.values.push_back(to_string(code));
1020     message.values.push_back(to_string(mask));
1021     message.values.push_back(to_string(layout));
1022
1023     pthread_mutex_lock(&g_ws_server_mutex);
1024     m_send_message_queue.push(message);
1025     pthread_mutex_unlock(&g_ws_server_mutex);
1026
1027     if (g_ws_server_context) {
1028         lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
1029     } else {
1030         LOGD("WARNING : g_ws_server_context is NULL");
1031     }
1032
1033     wait_for_reply_message();
1034
1035     std::vector<std::string> values;
1036     /* Check if we received reply for PROCESS_KEY_EVENT message */
1037     if (process_recved_messages_until_reply_found(
1038         ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_PROCESS_KEY_EVENT], values)) {
1039             if (ret) {
1040                 for (unsigned int loop = 0;loop < sizeof(ISE_TRUEFALSE_TYPES) / sizeof(ISE_TYPE_VALUE_STRING);loop++) {
1041                     if (values.at(0).compare(ISE_TRUEFALSE_TYPES[loop].type_string) == 0) {
1042                         *ret = ISE_TRUEFALSE_TYPES[loop].type_value;
1043                     }
1044                 }
1045             }
1046     }
1047     /* Now process the rest in the recv buffer */
1048     process_recved_messages();
1049 }
1050
1051 CWebHelperAgentWebSocket* CWebHelperAgentWebSocket::get_current_instance()
1052 {
1053     return m_current_instance;
1054 }
1055
1056 std::queue<ISE_MESSAGE>& CWebHelperAgentWebSocket::get_send_message_queue()
1057 {
1058     return m_send_message_queue;
1059 }
1060
1061 std::queue<ISE_MESSAGE>& CWebHelperAgentWebSocket::get_recv_message_queue()
1062 {
1063     return m_recv_message_queue;
1064 }
1065
1066 Ecore_Pipe* CWebHelperAgentWebSocket::get_message_pipe()
1067 {
1068     return m_message_pipe;
1069 }
1070
1071 void CWebHelperAgentWebSocket::wait_for_reply_message()
1072 {
1073     /* Let's wait for at most REPLY_TIMEOUT */
1074     struct timeval now;
1075     struct timespec timeout;
1076     gettimeofday(&now, NULL);
1077     timeout.tv_sec = now.tv_sec + REPLY_TIMEOUT.tv_sec;
1078     timeout.tv_nsec = (now.tv_usec + REPLY_TIMEOUT.tv_usec) * 1000;
1079     pthread_mutex_lock(&g_ws_query_mutex);
1080     pthread_cond_timedwait(&g_ws_query_condition, &g_ws_query_mutex, &timeout);
1081     pthread_mutex_unlock(&g_ws_query_mutex);
1082 }
1083
1084 void CWebHelperAgentWebSocket::process_recved_messages()
1085 {
1086     pthread_mutex_lock(&g_ws_server_mutex);
1087
1088     while (m_recv_message_queue.size() > 0) {
1089         ISE_MESSAGE &message = m_recv_message_queue.front();
1090
1091         handle_recved_message(message);
1092
1093         m_recv_message_queue.pop();
1094     }
1095
1096     pthread_mutex_unlock(&g_ws_server_mutex);
1097 }
1098
1099 bool CWebHelperAgentWebSocket::process_recved_messages_until_reply_found(std::string command, std::vector<std::string> &values)
1100 {
1101     bool ret = false;
1102
1103     pthread_mutex_lock(&g_ws_server_mutex);
1104
1105     while (ret == false && m_recv_message_queue.size() > 0) {
1106         ISE_MESSAGE &message = m_recv_message_queue.front();
1107
1108         if (message.command.compare(command) == 0 &&
1109             message.type.compare(ISE_MESSAGE_TYPE_STRINGS[ISE_MESSAGE_TYPE_REPLY]) == 0) {
1110             ret = true;
1111             values = message.values;
1112         }
1113         handle_recved_message(message);
1114
1115         m_recv_message_queue.pop();
1116     }
1117
1118     pthread_mutex_unlock(&g_ws_server_mutex);
1119
1120     return ret;
1121 }
1122
1123 void CWebHelperAgentWebSocket::handle_recved_message(ISE_MESSAGE &message)
1124 {
1125     static bool _key_event_processing = false;
1126     if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOG]) == 0) {
1127         std::string str = "";
1128         for (unsigned int loop = 0;loop < message.values.size();loop++) {
1129             str += message.values.at(loop).c_str();
1130             if (loop < message.values.size() - 1) {
1131                 str += " ";
1132             }
1133         }
1134         log(str.c_str());
1135     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_COMMIT_STRING]) == 0) {
1136         std::string str = "";
1137         for (unsigned int loop = 0;loop < message.values.size();loop++) {
1138             str += message.values.at(loop).c_str();
1139             if (loop < message.values.size() - 1) {
1140                 str += " ";
1141             }
1142         }
1143         if (_key_event_processing) {
1144             struct timeval tv;
1145             tv.tv_sec = 0;
1146             tv.tv_usec = 50000;
1147             select(0, NULL, NULL, NULL, &tv);
1148             _key_event_processing = false;
1149         }
1150         commit_string(str.c_str());
1151     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_UPDATE_PREEDIT_STRING]) == 0) {
1152         std::string str = "";
1153         for (unsigned int loop = 0;loop < message.values.size();loop++) {
1154             str += message.values.at(loop).c_str();
1155             if (loop < message.values.size() - 1) {
1156                 str += " ";
1157             }
1158         }
1159         update_preedit_string(str.c_str());
1160     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SEND_KEY_EVENT]) == 0) {
1161         if (message.values.size() == 1) {
1162             forward_key_event(atoi(message.values.at(0).c_str()));
1163             _key_event_processing = true;
1164         }
1165     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES]) == 0) {
1166         LOGD("ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES");
1167         int portrait_width, portrait_height;
1168         int landscape_width, landscape_height;
1169
1170         if (message.values.size() == 4 || message.values.size() == 2) {
1171             portrait_width = atoi(message.values.at(0).c_str());
1172             portrait_height = atoi(message.values.at(1).c_str());
1173             if (message.values.size() == 2) {
1174                 landscape_width = portrait_width;
1175                 landscape_height = portrait_height;
1176             } else {
1177                 landscape_width = atoi(message.values.at(2).c_str());
1178                 landscape_height = atoi(message.values.at(3).c_str());
1179             }
1180
1181             LOGD("ISE_MESSAGE_COMMAND_SET_KEYBOARD_SIZES : %d %d %d %d",
1182                 portrait_width, portrait_height, landscape_width, landscape_height);
1183
1184 #ifdef WAYLAND
1185             /* Since the full screen IME makes the client application fully obscured,
1186              * when it hides the client receives resume command and try to show IME again.
1187              * So here we are adjusting the height value when the requested keyboard size
1188              * is the same with the screen size, as a workaround */
1189             int scr_w = 0, scr_h = 0;
1190             ecore_wl2_sync();
1191             Ecore_Wl2_Display *ewd = NULL;
1192             if ((ewd = ecore_wl2_connected_display_get(NULL))) {
1193                 ecore_wl2_display_screen_size_get(ewd, &scr_w, &scr_h);
1194
1195                 if (scr_w == portrait_width && scr_h == portrait_height) {
1196                     portrait_height -= 1;
1197                 }
1198                 if (scr_h == landscape_width && scr_w == landscape_height) {
1199                     landscape_height -= 1;
1200                 }
1201             }
1202 #endif
1203
1204             set_keyboard_sizes(
1205                 portrait_width, portrait_height, landscape_width, landscape_height);
1206         }
1207     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_SET_SELECTION]) == 0) {
1208         LOGD("ISE_MESSAGE_COMMAND_SET_SELECTION");
1209         if (message.values.size() == 2) {
1210             LOGD("ISE_MESSAGE_COMMAND_SET_SELECTION : %d %d",
1211                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1212             set_selection(
1213                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1214         }
1215     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_SELECTION]) == 0) {
1216         if (message.values.size() == 0) {
1217             get_selection();
1218         }
1219     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT]) == 0) {
1220         LOGD("ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT");
1221         if (message.values.size() == 2) {
1222             LOGD("ISE_MESSAGE_COMMAND_GET_SURROUNDING_TEXT : %d %d",
1223                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1224             get_surrounding_text(
1225                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1226         }
1227     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT]) == 0) {
1228         LOGD("ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT");
1229         if (message.values.size() == 2) {
1230             LOGD("ISE_MESSAGE_COMMAND_DELETE_SURROUNDING_TEXT : %d %d",
1231                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1232             delete_surrounding_text(
1233                 atoi(message.values.at(0).c_str()), atoi(message.values.at(1).c_str()));
1234         }
1235     } else if (message.command.compare(ISE_MESSAGE_COMMAND_STRINGS[ISE_MESSAGE_COMMAND_LOGIN]) == 0) {
1236         if (g_ws_server_context) {
1237             lws_callback_on_writable_all_protocol(g_ws_server_context, &protocols[PROTOCOL_KEYBOARD]);
1238         } else {
1239             LOGD("WARNING : g_ws_server_context is NULL");
1240         }
1241     }
1242 }